docsets.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002  *
00003  * Copyright (C) 1997-2008 by Dimitri van Heesch.
00004  *
00005  * Permission to use, copy, modify, and distribute this software and its
00006  * documentation under the terms of the GNU General Public License is hereby 
00007  * granted. No representations are made about the suitability of this software 
00008  * for any purpose. It is provided "as is" without express or implied warranty.
00009  * See the GNU General Public License for more details.
00010  *
00011  * Documents produced by Doxygen are derivative works derived from the
00012  * input used in their production; they are not affected by this license.
00013  *
00014  */
00015 
00016 #include "docsets.h"
00017 #include "config.h"
00018 #include "message.h"
00019 #include "doxygen.h"
00020 #include <qfile.h>
00021 
00022 
00023 DocSets::DocSets() : m_nodes(17), m_scopes(17)
00024 {
00025   m_nf = 0;
00026   m_tf = 0;
00027   m_dc = 0;
00028   m_id = 0;
00029   m_nodes.setAutoDelete(TRUE);
00030 }
00031 
00032 DocSets::~DocSets()
00033 {
00034   delete m_nf;
00035   delete m_tf;
00036 }
00037 
00038 void DocSets::initialize()
00039 {
00040   // -- get config options
00041   QCString projectName = Config_getString("PROJECT_NAME");
00042   if (projectName.isEmpty()) projectName="root";
00043   QCString bundleId = Config_getString("DOCSET_BUNDLE_ID");
00044   if (bundleId.isEmpty()) bundleId="org.doxygen.Project";
00045   QCString feedName = Config_getString("DOCSET_FEEDNAME");
00046   if (feedName.isEmpty()) feedName="FeedName";
00047 
00048   // -- write Makefile
00049   {
00050   QCString mfName = Config_getString("HTML_OUTPUT") + "/Makefile";
00051   QFile makefile(mfName);
00052   if (!makefile.open(IO_WriteOnly))
00053   {
00054     err("Could not open file %s for writing\n",mfName.data());
00055     exit(1);
00056   }
00057   QTextStream ts(&makefile);
00058   ts.setEncoding(QTextStream::UnicodeUTF8);
00059 
00060   ts << "DOCSET_NAME=" << bundleId << ".docset\n" 
00061         "DOCSET_CONTENTS=$(DOCSET_NAME)/Contents\n"
00062         "DOCSET_RESOURCES=$(DOCSET_CONTENTS)/Resources\n"
00063         "DOCSET_DOCUMENTS=$(DOCSET_RESOURCES)/Documents\n"
00064         "DOCSET_INSTALL=~/Library/Developer/Shared/Documentation/DocSets\n"
00065         "XCODE_INSTALL=$(shell xcode-select -print-path)\n"
00066         "\n"
00067         "all: docset\n"
00068         "\n"
00069         "docset:\n"
00070         "\tmkdir -p $(DOCSET_DOCUMENTS)\n"
00071         "\tcp Nodes.xml $(DOCSET_RESOURCES)\n"
00072         "\tcp Tokens.xml $(DOCSET_RESOURCES)\n"
00073         "\tcp Info.plist $(DOCSET_CONTENTS)\n"
00074         "\ttar --exclude $(DOCSET_NAME) \\\n"
00075         "\t    --exclude Nodes.xml \\\n"
00076         "\t    --exclude Tokens.xml \\\n"
00077         "\t    --exclude Info.plist \\\n"
00078         "\t    --exclude Makefile -c -f - . \\\n"
00079         "\t    | (cd $(DOCSET_DOCUMENTS); tar xvf -)\n"
00080         "\t$(XCODE_INSTALL)/usr/bin/docsetutil index $(DOCSET_NAME)\n"
00081         "\trm -f $(DOCSET_DOCUMENTS)/Nodes.xml\n"
00082         "\trm -f $(DOCSET_DOCUMENTS)/Info.plist\n"
00083         "\trm -f $(DOCSET_DOCUMENTS)/Makefile\n"
00084         "\trm -f $(DOCSET_RESOURCES)/Nodes.xml\n"
00085         "\trm -f $(DOCSET_RESOURCES)/Tokens.xml\n"
00086         "\n"
00087         "install: docset\n"
00088         "\tmkdir -p $(DOCSET_INSTALL)\n"
00089         "\tcp -R $(DOCSET_NAME) $(DOCSET_INSTALL)\n"
00090         "\n"
00091         "uninstall:\n"
00092         "\trm -rf $(DOCSET_INSTALL)\n"
00093         "\n"
00094         "always:\n";
00095   }
00096 
00097   // -- write Info.plist
00098   {
00099   QCString plName = Config_getString("HTML_OUTPUT") + "/Info.plist";
00100   QFile plist(plName);
00101   if (!plist.open(IO_WriteOnly))
00102   {
00103     err("Could not open file %s for writing\n",plName.data());
00104     exit(1);
00105   }
00106   QTextStream ts(&plist);
00107   ts.setEncoding(QTextStream::UnicodeUTF8);
00108 
00109   ts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 
00110         "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\"\n" 
00111         "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" 
00112         "<plist version=\"1.0\">\n" 
00113         "<dict>\n" 
00114         "     <key>CFBundleName</key>\n" 
00115         "     <string>" << projectName << "</string>\n" 
00116         "     <key>CFBundleIdentifier</key>\n"
00117         "     <string>" << bundleId << ".docset</string>\n" 
00118         "     <key>DocSetFeedName</key>\n" 
00119         "     <string>" << feedName << "</string>\n"
00120         "</dict>\n"
00121         "</plist>\n";
00122   }
00123 
00124   // -- start Nodes.xml
00125   QCString notes = Config_getString("HTML_OUTPUT") + "/Nodes.xml";
00126   m_nf = new QFile(notes);
00127   if (!m_nf->open(IO_WriteOnly))
00128   {
00129     err("Could not open file %s for writing\n",notes.data());
00130     exit(1);
00131   }
00132   QCString indexName="index";
00133   if (Config_getBool("GENERATE_TREEVIEW")) indexName="main";
00134   m_nts.setDevice(m_nf);
00135   m_nts.setEncoding(QTextStream::UnicodeUTF8);
00136   m_nts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
00137   m_nts << "<DocSetNodes version=\"1.0\">" << endl;
00138   m_nts << "  <TOC>" << endl;
00139   m_nts << "    <Node>" << endl;
00140   m_nts << "      <Name>Root</Name>" << endl;
00141   m_nts << "      <Path>" << indexName << Doxygen::htmlFileExtension << "</Path>" << endl;
00142   m_nts << "      <Subnodes>" << endl;
00143   m_dc = 1;
00144   m_firstNode.resize(m_dc);
00145   m_firstNode.at(0)=TRUE;
00146 
00147   QCString tokens = Config_getString("HTML_OUTPUT") + "/Tokens.xml";
00148   m_tf = new QFile(tokens);
00149   if (!m_tf->open(IO_WriteOnly))
00150   {
00151     err("Could not open file %s for writing\n",tokens.data());
00152     exit(1);
00153   }
00154   m_tts.setDevice(m_tf);
00155   m_tts.setEncoding(QTextStream::UnicodeUTF8);
00156   m_tts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
00157   m_tts << "<Tokens version=\"1.0\">" << endl;
00158 }
00159 
00160 void DocSets::finalize()
00161 {
00162   m_nts << indent() << " </Node>" << endl;
00163   m_dc--;
00164   m_nts << "      </Subnodes>" << endl;
00165   m_nts << "    </Node>" << endl;
00166   m_nts << "  </TOC>" << endl;
00167   m_nts << "</DocSetNodes>" << endl;
00168   m_nf->close();
00169   delete m_nf;
00170   m_nf=0;
00171 
00172   m_tts << "</Tokens>" << endl;
00173   m_tf->close();
00174   delete m_tf;
00175   m_tf=0;
00176 }
00177 
00178 QCString DocSets::indent()
00179 {
00180   QCString result;
00181   result.fill(' ',(m_dc+2)*2);
00182   return result;
00183 }
00184 
00185 void DocSets::incContentsDepth()
00186 {
00187   ++m_dc;
00188   m_nts << indent() << "<Subnodes>" << endl;
00189   m_firstNode.resize(m_dc);
00190   if (m_dc>0)
00191   {
00192     m_firstNode.at(m_dc-1)=TRUE;
00193   }
00194 }
00195 
00196 void DocSets::decContentsDepth()
00197 {
00198   if (!m_firstNode.at(m_dc-1))
00199   {
00200     m_nts << indent() << " </Node>" << endl;
00201   }
00202   m_nts << indent() << "</Subnodes>" << endl;
00203   --m_dc;
00204 }
00205 
00206 void DocSets::addContentsItem(bool isDir,
00207                               const char *name, 
00208                               const char *ref, 
00209                               const char *file,
00210                               const char *anchor)
00211 {
00212   (void)isDir;
00213   if (file && ref==0)
00214   {
00215     if (!m_firstNode.at(m_dc-1))
00216     {
00217       m_nts << indent() << " </Node>" << endl;
00218     }
00219     m_firstNode.at(m_dc-1)=FALSE;
00220     m_nts << indent() << " <Node>" << endl;
00221     m_nts << indent() << "  <Name>" << convertToXML(name) << "</Name>" << endl;
00222     m_nts << indent() << "  <Path>" << file << Doxygen::htmlFileExtension;
00223     if (anchor)
00224     {
00225       m_nts << "#" << anchor;
00226     }
00227     m_nts << "</Path>" << endl;
00228   }
00229 }
00230 
00231 void DocSets::addIndexItem(const char *, const char *, 
00232                            const char *, const char *,
00233                            const char *,const MemberDef *md)
00234 {
00235   if (!md->isLinkable()) return; // internal symbol
00236 
00237   ClassDef *cd     = md->getClassDef();
00238   NamespaceDef *nd = md->getNamespaceDef();
00239   FileDef  *fd     = md->getFileDef();
00240 
00241   // determine language
00242   QCString lang;
00243   SrcLangExt langExt = SrcLangExt_Cpp;
00244   if (fd) langExt = getLanguageFromFileName(fd->name());
00245   switch (langExt)
00246   {
00247     case SrcLangExt_Cpp:
00248       {
00249         if (md->isObjCMethod())                        
00250           lang="occ";  // Objective C/C++
00251         else if (fd && fd->name().right(2).lower()==".c") 
00252           lang="c";    // Plain C
00253         else                                      
00254           lang="cpp";  // C++
00255       }
00256       break;
00257     case SrcLangExt_ObjC:   lang="occ"; break;        // Objective C++
00258     case SrcLangExt_IDL:    lang="idl"; break;        // IDL
00259     case SrcLangExt_CSharp: lang="csharp"; break;     // C#
00260     case SrcLangExt_PHP:    lang="php"; break;        // PHP4/5
00261     case SrcLangExt_D:      lang="d"; break;          // D
00262     case SrcLangExt_Java:   lang="java"; break;       // Java
00263     case SrcLangExt_JS:     lang="javascript"; break; // Javascript
00264     case SrcLangExt_Python: lang="python"; break;     // Python
00265     case SrcLangExt_F90:    lang="fortran"; break;    // Fortran
00266     case SrcLangExt_VHDL:   lang="vhdl"; break;       // VHDL
00267   }
00268 
00269   // determine scope
00270   QCString scope;
00271   QCString type;
00272   QCString decl;
00273   Definition *d = 0;
00274   if (fd && fd->isLinkable() && m_scopes.find(fd->getOutputFileBase())==0)
00275   {
00276     writeToken(m_tts,fd,"file",lang,0,0,0);
00277     m_scopes.append(fd->getOutputFileBase(),(void*)0x8);
00278   }
00279   if (cd) 
00280   {
00281     scope = cd->qualifiedName();
00282     if (cd->isTemplate()) 
00283       type="tmplt";
00284     else if (cd->compoundType()==ClassDef::Interface) 
00285       type="intf";
00286     else if (cd->compoundType()==ClassDef::Category)
00287       type="cat";
00288     else 
00289       type = "cl";
00290     d = cd;
00291     IncludeInfo *ii = cd->includeInfo();
00292     if (ii)
00293     {
00294       decl=ii->includeName;
00295       if (decl.isEmpty())
00296       {
00297         decl=ii->local;
00298       }
00299     }
00300   }
00301   else if (nd) 
00302   {
00303     scope = nd->name();
00304     type = "ns";
00305     d = cd;
00306   }
00307   if (d && d->isLinkable() && m_scopes.find(d->getOutputFileBase())==0)
00308   {
00309     writeToken(m_tts,d,type,lang,0,0,decl);
00310     m_scopes.append(d->getOutputFileBase(),(void*)0x8);
00311   }
00312 
00313   switch (md->memberType())
00314   {
00315     case MemberDef::Define:
00316       type="macro"; break;
00317     case MemberDef::Function:
00318       if (cd && cd->compoundType()==ClassDef::Interface) 
00319         type="intfm";
00320       else if (cd && cd->compoundType()==ClassDef::Class) 
00321         type="clm"; 
00322       else 
00323         type="func"; 
00324       break;
00325     case MemberDef::Variable:
00326       type="data"; break;
00327     case MemberDef::Typedef:
00328       type="tdef"; break;
00329     case MemberDef::Enumeration:
00330       type="enum"; break;
00331     case MemberDef::EnumValue:
00332       type="econst"; break;
00333     case MemberDef::Prototype:
00334       type="prototype"; break;
00335     case MemberDef::Signal:
00336       type="signal"; break;
00337     case MemberDef::Slot:
00338       type="slot"; break;
00339     case MemberDef::Friend:
00340       type="ffunc"; break;
00341     case MemberDef::DCOP:
00342       type="dcop"; break;
00343     case MemberDef::Property:
00344       type="property"; break;
00345     case MemberDef::Event:
00346       type="event"; break;
00347   }
00348   writeToken(m_tts,md,type,lang,scope,md->anchor());
00349 }
00350 
00351 void DocSets::writeToken(QTextStream &t,
00352                          const Definition *d,
00353                          const QCString &type,
00354                          const QCString &lang,
00355                          const char *scope,
00356                          const char *anchor,
00357                          const char *decl)
00358 {
00359   t << "  <Token>" << endl;
00360   t << "    <TokenIdentifier>" << endl;
00361   t << "      <Name>" << convertToXML(d->name()) << "</Name>" << endl;
00362   t << "      <APILanguage>" << lang << "</APILanguage>" << endl;
00363   t << "      <Type>" << type << "</Type>" << endl;
00364   t << "      <Scope>" << convertToXML(scope) << "</Scope>" << endl;
00365   t << "    </TokenIdentifier>" << endl;
00366   t << "    <Path>" << d->getOutputFileBase() 
00367                     << Doxygen::htmlFileExtension << "</Path>" << endl;
00368   if (anchor)
00369   {
00370     t << "    <Anchor>" << anchor << "</Anchor>" << endl;
00371   }
00372   QCString tooltip = d->briefDescriptionAsTooltip();
00373   if (!tooltip.isEmpty())
00374   {
00375     t << "    <Abstract>" << tooltip << "</Abstract>" << endl;
00376   }
00377   if (decl)
00378   {
00379     t << "    <DeclaredIn>" << convertToXML(decl) << "</DeclaredIn>" << endl;
00380   }
00381   t << "  </Token>" << endl;
00382 }
00383 
00384 void DocSets::addIndexFile(const char *name)
00385 {
00386   (void)name;
00387 }
00388 



Generated on Mon Mar 31 10:58:35 2008 by  doxygen 1.5.1