docsets.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * Copyright (C) 1997-2015 by Dimitri van Heesch.
4  *
5  * Permission to use, copy, modify, and distribute this software and its
6  * documentation under the terms of the GNU General Public License is hereby
7  * granted. No representations are made about the suitability of this software
8  * for any purpose. It is provided "as is" without express or implied warranty.
9  * See the GNU General Public License for more details.
10  *
11  * Documents produced by Doxygen are derivative works derived from the
12  * input used in their production; they are not affected by this license.
13  *
14  */
15 
16 #include <qfile.h>
17 #include "docsets.h"
18 #include "config.h"
19 #include "message.h"
20 #include "doxygen.h"
21 #include "groupdef.h"
22 #include "classdef.h"
23 #include "filedef.h"
24 #include "memberdef.h"
25 #include "namespacedef.h"
26 #include "util.h"
27 
28 DocSets::DocSets() : m_nodes(17), m_scopes(17)
29 {
30  m_nf = 0;
31  m_tf = 0;
32  m_dc = 0;
33  m_id = 0;
34  m_nodes.setAutoDelete(TRUE);
35 }
36 
38 {
39  delete m_nf;
40  delete m_tf;
41 }
42 
44 {
45  // -- get config options
46  QCString projectName = Config_getString("PROJECT_NAME");
47  if (projectName.isEmpty()) projectName="root";
48  QCString bundleId = Config_getString("DOCSET_BUNDLE_ID");
49  if (bundleId.isEmpty()) bundleId="org.doxygen.Project";
50  QCString feedName = Config_getString("DOCSET_FEEDNAME");
51  if (feedName.isEmpty()) feedName="FeedName";
52  QCString publisherId = Config_getString("DOCSET_PUBLISHER_ID");
53  if (publisherId.isEmpty()) publisherId="PublisherId";
54  QCString publisherName = Config_getString("DOCSET_PUBLISHER_NAME");
55  if (publisherName.isEmpty()) publisherName="PublisherName";
56  QCString projectNumber = Config_getString("PROJECT_NUMBER");
57  if (projectNumber.isEmpty()) projectNumber="ProjectNumber";
58 
59  // -- write Makefile
60  {
61  QCString mfName = Config_getString("HTML_OUTPUT") + "/Makefile";
62  QFile makefile(mfName);
63  if (!makefile.open(IO_WriteOnly))
64  {
65  err("Could not open file %s for writing\n",mfName.data());
66  exit(1);
67  }
68  FTextStream ts(&makefile);
69 
70  ts << "DOCSET_NAME=" << bundleId << ".docset\n"
71  "DOCSET_CONTENTS=$(DOCSET_NAME)/Contents\n"
72  "DOCSET_RESOURCES=$(DOCSET_CONTENTS)/Resources\n"
73  "DOCSET_DOCUMENTS=$(DOCSET_RESOURCES)/Documents\n"
74  "DESTDIR=~/Library/Developer/Shared/Documentation/DocSets\n"
75  "XCODE_INSTALL=\"$(shell xcode-select -print-path)\"\n"
76  "\n"
77  "all: docset\n"
78  "\n"
79  "docset:\n"
80  "\tmkdir -p $(DOCSET_DOCUMENTS)\n"
81  "\tcp Nodes.xml $(DOCSET_RESOURCES)\n"
82  "\tcp Tokens.xml $(DOCSET_RESOURCES)\n"
83  "\tcp Info.plist $(DOCSET_CONTENTS)\n"
84  "\ttar --exclude $(DOCSET_NAME) \\\n"
85  "\t --exclude Nodes.xml \\\n"
86  "\t --exclude Tokens.xml \\\n"
87  "\t --exclude Info.plist \\\n"
88  "\t --exclude Makefile -c -f - . \\\n"
89  "\t | (cd $(DOCSET_DOCUMENTS); tar xvf -)\n"
90  "\t$(XCODE_INSTALL)/usr/bin/docsetutil index $(DOCSET_NAME)\n"
91  "\trm -f $(DOCSET_DOCUMENTS)/Nodes.xml\n"
92  "\trm -f $(DOCSET_DOCUMENTS)/Info.plist\n"
93  "\trm -f $(DOCSET_DOCUMENTS)/Makefile\n"
94  "\trm -f $(DOCSET_RESOURCES)/Nodes.xml\n"
95  "\trm -f $(DOCSET_RESOURCES)/Tokens.xml\n"
96  "\n"
97  "clean:\n"
98  "\trm -rf $(DOCSET_NAME)\n"
99  "\n"
100  "install: docset\n"
101  "\tmkdir -p $(DESTDIR)\n"
102  "\tcp -R $(DOCSET_NAME) $(DESTDIR)\n"
103  "\n"
104  "uninstall:\n"
105  "\trm -rf $(DESTDIR)/$(DOCSET_NAME)\n"
106  "\n"
107  "always:\n";
108  }
109 
110  // -- write Info.plist
111  {
112  QCString plName = Config_getString("HTML_OUTPUT") + "/Info.plist";
113  QFile plist(plName);
114  if (!plist.open(IO_WriteOnly))
115  {
116  err("Could not open file %s for writing\n",plName.data());
117  exit(1);
118  }
119  FTextStream ts(&plist);
120 
121  ts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
122  "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\"\n"
123  "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
124  "<plist version=\"1.0\">\n"
125  "<dict>\n"
126  " <key>CFBundleName</key>\n"
127  " <string>" << projectName << "</string>\n"
128  " <key>CFBundleIdentifier</key>\n"
129  " <string>" << bundleId << "</string>\n"
130  " <key>CFBundleVersion</key>\n"
131  " <string>" << projectNumber << "</string>\n"
132  " <key>DocSetFeedName</key>\n"
133  " <string>" << feedName << "</string>\n"
134  " <key>DocSetPublisherIdentifier</key>\n"
135  " <string>" << publisherId << "</string>\n"
136  " <key>DocSetPublisherName</key>\n"
137  " <string>" << publisherName << "</string>\n"
138  // markers for Dash
139  " <key>DashDocSetFamily</key>\n"
140  " <string>doxy</string>\n"
141  " <key>DocSetPlatformFamily</key>\n"
142  " <string>doxygen</string>\n"
143  "</dict>\n"
144  "</plist>\n";
145  }
146 
147  // -- start Nodes.xml
148  QCString notes = Config_getString("HTML_OUTPUT") + "/Nodes.xml";
149  m_nf = new QFile(notes);
150  if (!m_nf->open(IO_WriteOnly))
151  {
152  err("Could not open file %s for writing\n",notes.data());
153  exit(1);
154  }
155  //QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index";
156  QCString indexName="index";
158  m_nts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
159  m_nts << "<DocSetNodes version=\"1.0\">" << endl;
160  m_nts << " <TOC>" << endl;
161  m_nts << " <Node>" << endl;
162  m_nts << " <Name>Root</Name>" << endl;
163  m_nts << " <Path>" << indexName << Doxygen::htmlFileExtension << "</Path>" << endl;
164  m_nts << " <Subnodes>" << endl;
165  m_dc = 1;
167  m_firstNode.at(0)=TRUE;
168 
169  QCString tokens = Config_getString("HTML_OUTPUT") + "/Tokens.xml";
170  m_tf = new QFile(tokens);
171  if (!m_tf->open(IO_WriteOnly))
172  {
173  err("Could not open file %s for writing\n",tokens.data());
174  exit(1);
175  }
177  m_tts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
178  m_tts << "<Tokens version=\"1.0\">" << endl;
179 }
180 
182 {
183  if (!m_firstNode.at(m_dc-1))
184  {
185  m_nts << indent() << " </Node>" << endl;
186  }
187  m_dc--;
188  m_nts << " </Subnodes>" << endl;
189  m_nts << " </Node>" << endl;
190  m_nts << " </TOC>" << endl;
191  m_nts << "</DocSetNodes>" << endl;
192  m_nf->close();
193  delete m_nf;
194  m_nf=0;
195 
196  m_tts << "</Tokens>" << endl;
197  m_tf->close();
198  delete m_tf;
199  m_tf=0;
200 }
201 
203 {
205  result.fill(' ',(m_dc+2)*2);
206  return result;
207 }
208 
210 {
211  //printf("DocSets::incContentsDepth() m_dc=%d\n",m_dc);
212  ++m_dc;
213  m_nts << indent() << "<Subnodes>" << endl;
215  if (m_dc>0)
216  {
217  m_firstNode.at(m_dc-1)=TRUE;
218  }
219 }
220 
222 {
223  if (!m_firstNode.at(m_dc-1))
224  {
225  m_nts << indent() << " </Node>" << endl;
226  }
227  m_nts << indent() << "</Subnodes>" << endl;
228  --m_dc;
229  //printf("DocSets::decContentsDepth() m_dc=%d\n",m_dc);
230 }
231 
232 void DocSets::addContentsItem(bool isDir,
233  const char *name,
234  const char *ref,
235  const char *file,
236  const char *anchor,
237  bool /* separateIndex */,
238  bool /* addToNavIndex */,
239  Definition * /*def*/)
240 {
241  (void)isDir;
242  //printf("DocSets::addContentsItem(%s) m_dc=%d\n",name,m_dc);
243  if (ref==0)
244  {
245  if (!m_firstNode.at(m_dc-1))
246  {
247  m_nts << indent() << " </Node>" << endl;
248  }
250  m_nts << indent() << " <Node>" << endl;
251  m_nts << indent() << " <Name>" << convertToXML(name) << "</Name>" << endl;
252  if (file && file[0]=='^') // URL marker
253  {
254  m_nts << indent() << " <URL>" << convertToXML(&file[1])
255  << "</URL>" << endl;
256  }
257  else // relative file
258  {
259  m_nts << indent() << " <Path>";
260  if (file && file[0]=='!') // user specified file
261  {
262  m_nts << convertToXML(&file[1]);
263  }
264  else if (file) // doxygen generated file
265  {
267  }
268  m_nts << "</Path>" << endl;
269  if (file && anchor)
270  {
271  m_nts << indent() << " <Anchor>" << anchor << "</Anchor>" << endl;
272  }
273  }
274  }
275 }
276 
278  const char *,const char *)
279 {
280  if (md==0 && context==0) return;
281 
282  FileDef *fd = 0;
283  ClassDef *cd = 0;
284  NamespaceDef *nd = 0;
285 
286  if (md)
287  {
288  fd = md->getFileDef();
289  cd = md->getClassDef();
290  nd = md->getNamespaceDef();
291  if (!md->isLinkable()) return; // internal symbol
292  }
293 
294  QCString scope;
295  QCString type;
296  QCString decl;
297 
298  // determine language
299  QCString lang;
300  SrcLangExt langExt = SrcLangExt_Cpp;
301  if (md)
302  {
303  langExt = md->getLanguage();
304  }
305  else if (context)
306  {
307  langExt = context->getLanguage();
308  }
309  switch (langExt)
310  {
311  case SrcLangExt_Cpp:
312  case SrcLangExt_ObjC:
313  {
314  if (md && (md->isObjCMethod() || md->isObjCProperty()))
315  lang="occ"; // Objective C/C++
316  else if (fd && fd->name().right(2).lower()==".c")
317  lang="c"; // Plain C
318  else if (cd==0 && nd==0)
319  lang="c"; // Plain C symbol outside any class or namespace
320  else
321  lang="cpp"; // C++
322  }
323  break;
324  case SrcLangExt_IDL: lang="idl"; break; // IDL
325  case SrcLangExt_CSharp: lang="csharp"; break; // C#
326  case SrcLangExt_PHP: lang="php"; break; // PHP4/5
327  case SrcLangExt_D: lang="d"; break; // D
328  case SrcLangExt_Java: lang="java"; break; // Java
329  case SrcLangExt_JS: lang="javascript"; break; // Javascript
330  case SrcLangExt_Python: lang="python"; break; // Python
331  case SrcLangExt_Fortran: lang="fortran"; break; // Fortran
332  case SrcLangExt_VHDL: lang="vhdl"; break; // VHDL
333  case SrcLangExt_XML: lang="xml"; break; // DBUS XML
334  case SrcLangExt_Tcl: lang="tcl"; break; // Tcl
335  case SrcLangExt_Markdown:lang="markdown"; break; // Markdown
336  case SrcLangExt_Unknown: lang="unknown"; break; // should not happen!
337  }
338 
339  if (md)
340  {
341  if (context==0)
342  {
343  if (md->getGroupDef())
344  context = md->getGroupDef();
345  else if (md->getFileDef())
346  context = md->getFileDef();
347  }
348  if (context==0) return; // should not happen
349 
350  switch (md->memberType())
351  {
352  case MemberType_Define:
353  type="macro"; break;
354  case MemberType_Function:
355  if (cd && (cd->compoundType()==ClassDef::Interface ||
357  {
358  if (md->isStatic())
359  type="clm"; // class member
360  else
361  type="instm"; // instance member
362  }
363  else if (cd && cd->compoundType()==ClassDef::Protocol)
364  {
365  if (md->isStatic())
366  type="intfcm"; // interface class member
367  else
368  type="intfm"; // interface member
369  }
370  else
371  type="func";
372  break;
373  case MemberType_Variable:
374  type="data"; break;
375  case MemberType_Typedef:
376  type="tdef"; break;
378  type="enum"; break;
380  type="econst"; break;
381  //case MemberDef::Prototype:
382  // type="prototype"; break;
383  case MemberType_Signal:
384  type="signal"; break;
385  case MemberType_Slot:
386  type="slot"; break;
387  case MemberType_Friend:
388  type="ffunc"; break;
389  case MemberType_DCOP:
390  type="dcop"; break;
391  case MemberType_Property:
392  if (cd && cd->compoundType()==ClassDef::Protocol)
393  type="intfp"; // interface property
394  else
395  type="instp"; // instance property
396  break;
397  case MemberType_Event:
398  type="event"; break;
400  type="ifc"; break;
401  case MemberType_Service:
402  type="svc"; break;
403  }
404  cd = md->getClassDef();
405  nd = md->getNamespaceDef();
406  if (cd)
407  {
408  scope = cd->qualifiedName();
409  }
410  else if (nd)
411  {
412  scope = nd->name();
413  }
414  MemberDef *declMd = md->memberDeclaration();
415  if (declMd==0) declMd = md;
416  {
417  fd = md->getFileDef();
418  if (fd)
419  {
420  decl = fd->name();
421  }
422  }
423  writeToken(m_tts,md,type,lang,scope,md->anchor(),decl);
424  }
425  else if (context && context->isLinkable())
426  {
427  if (fd==0 && context->definitionType()==Definition::TypeFile)
428  {
429  fd = (FileDef*)context;
430  }
431  if (cd==0 && context->definitionType()==Definition::TypeClass)
432  {
433  cd = (ClassDef*)context;
434  }
435  if (nd==0 && context->definitionType()==Definition::TypeNamespace)
436  {
437  nd = (NamespaceDef*)context;
438  }
439  if (fd)
440  {
441  type="file";
442  }
443  else if (cd)
444  {
445  scope = cd->qualifiedName();
446  if (cd->isTemplate())
447  {
448  type="tmplt";
449  }
450  else if (cd->compoundType()==ClassDef::Protocol)
451  {
452  type="intf";
453  if (scope.right(2)=="-p") scope=scope.left(scope.length()-2);
454  }
455  else if (cd->compoundType()==ClassDef::Interface)
456  {
457  type="cl";
458  }
459  else if (cd->compoundType()==ClassDef::Category)
460  {
461  type="cat";
462  }
463  else
464  {
465  type = "cl";
466  }
467  IncludeInfo *ii = cd->includeInfo();
468  if (ii)
469  {
470  decl=ii->includeName;
471  }
472  }
473  else if (nd)
474  {
475  scope = nd->name();
476  type = "ns";
477  }
478  if (m_scopes.find(context->getOutputFileBase())==0)
479  {
480  writeToken(m_tts,context,type,lang,scope,0,decl);
481  m_scopes.append(context->getOutputFileBase(),(void*)0x8);
482  }
483  }
484 }
485 
487  const Definition *d,
488  const QCString &type,
489  const QCString &lang,
490  const char *scope,
491  const char *anchor,
492  const char *decl)
493 {
494  t << " <Token>" << endl;
495  t << " <TokenIdentifier>" << endl;
496  QCString name = d->name();
497  if (name.right(2)=="-p") name=name.left(name.length()-2);
498  t << " <Name>" << convertToXML(name) << "</Name>" << endl;
499  if (!lang.isEmpty())
500  {
501  t << " <APILanguage>" << lang << "</APILanguage>" << endl;
502  }
503  if (!type.isEmpty())
504  {
505  t << " <Type>" << type << "</Type>" << endl;
506  }
507  if (scope)
508  {
509  t << " <Scope>" << convertToXML(scope) << "</Scope>" << endl;
510  }
511  t << " </TokenIdentifier>" << endl;
512  t << " <Path>" << d->getOutputFileBase()
513  << Doxygen::htmlFileExtension << "</Path>" << endl;
514  if (anchor)
515  {
516  t << " <Anchor>" << anchor << "</Anchor>" << endl;
517  }
518  QCString tooltip = d->briefDescriptionAsTooltip();
519  if (!tooltip.isEmpty())
520  {
521  t << " <Abstract>" << convertToXML(tooltip) << "</Abstract>" << endl;
522  }
523  if (decl)
524  {
525  t << " <DeclaredIn>" << convertToXML(decl) << "</DeclaredIn>" << endl;
526  }
527  t << " </Token>" << endl;
528 }
529 
530 void DocSets::addIndexFile(const char *name)
531 {
532  (void)name;
533 }
534 
static QCString name
Definition: declinfo.cpp:673
QCString convertToXML(const char *s)
Definition: util.cpp:5717
CompoundType compoundType() const
Definition: classdef.cpp:4394
virtual bool isLinkable() const =0
~DocSets()
Definition: docsets.cpp:37
static QCString scope
Definition: declinfo.cpp:668
IncludeInfo * includeInfo() const
Definition: classdef.cpp:4449
static QCString result
bool isEmpty() const
Definition: qcstring.h:189
uint length() const
Definition: qcstring.h:195
#define IO_WriteOnly
Definition: qiodevice.h:62
static QCString htmlFileExtension
Definition: doxygen.h:130
bool resize(uint size)
Definition: qarray.h:69
void setDevice(QIODevice *)
void addContentsItem(bool isDir, const char *name, const char *ref, const char *file, const char *anchor, bool separateIndex, bool addToNavIndex, Definition *def)
Definition: docsets.cpp:232
void incContentsDepth()
Definition: docsets.cpp:209
const bool FALSE
Definition: qglobal.h:370
QCString left(uint len) const
Definition: qcstring.cpp:213
Simplified and optimized version of QTextStream.
Definition: ftextstream.h:11
void addIndexItem(Definition *context, MemberDef *md, const char *sectionAnchor, const char *title)
Definition: docsets.cpp:277
virtual QCString getOutputFileBase() const =0
DocSets()
Definition: docsets.cpp:28
void append(const char *key, const T *d)
Definition: sortdict.h:135
SDict< NodeDef > m_nodes
Definition: docsets.h:81
bool isObjCProperty() const
Definition: memberdef.cpp:3962
SrcLangExt
Definition: types.h:41
QFile * m_tf
Definition: docsets.h:75
QFile * m_nf
Definition: docsets.h:74
void decContentsDepth()
Definition: docsets.cpp:221
FileDef * getFileDef() const
Definition: memberdef.cpp:4075
virtual DefType definitionType() const =0
void addIndexFile(const char *name)
Definition: docsets.cpp:530
const QCString & name() const
Definition: definition.h:114
SDict< void > m_scopes
Definition: docsets.h:82
QCString name() const
Definition: filedef.cpp:1193
bool isTemplate() const
Definition: classdef.cpp:4444
QCString right(uint len) const
Definition: qcstring.cpp:231
SrcLangExt getLanguage() const
bool open(int)
Definition: qfile_unix.cpp:134
QCString indent()
Definition: docsets.cpp:202
A bunch of utility functions.
const char * data() const
Definition: qcstring.h:207
QCString anchor() const
Definition: memberdef.cpp:1031
#define Config_getString(val)
Definition: config.cpp:660
QCString includeName
Definition: filedef.h:50
ClassDef * getClassDef() const
Definition: memberdef.cpp:4070
bool isObjCMethod() const
Definition: memberdef.cpp:3956
virtual QCString qualifiedName() const
QArray< bool > m_firstNode
Definition: docsets.h:80
FTextStream m_tts
Definition: docsets.h:77
void err(const char *fmt,...)
Definition: message.cpp:226
MemberType memberType() const
Definition: memberdef.cpp:4125
The QFile class is an I/O device that operates on files.
Definition: qfile.h:50
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)
Definition: docsets.cpp:486
FTextStream m_nts
Definition: docsets.h:76
GroupDef * getGroupDef() const
Definition: memberdef.cpp:4095
int m_dc
Definition: docsets.h:78
MemberDef * memberDeclaration() const
Definition: memberdef.cpp:4598
int m_id
Definition: docsets.h:79
static QCString type
Definition: declinfo.cpp:672
bool fill(char c, int len=-1)
Definition: qcstring.h:243
void finalize()
Definition: docsets.cpp:181
NamespaceDef * getNamespaceDef() const
Definition: memberdef.cpp:4080
QCString briefDescriptionAsTooltip() const
void initialize()
Definition: docsets.cpp:43
QCString lower() const
Definition: qcstring.cpp:263
bool isStatic() const
Definition: memberdef.cpp:4205
T * find(const char *key)
Definition: sortdict.h:232
void close()
Definition: qfile_unix.cpp:614
type & at(uint i) const
Definition: qarray.h:98
bool isLinkable() const
Definition: memberdef.cpp:1161
const bool TRUE
Definition: qglobal.h:371
QTextStream & endl(QTextStream &s)