Doxygen
Loading...
Searching...
No Matches
docsets.cpp
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2021 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// own header
17#include "docsets.h"
18
19// standard includes
20#include <stack>
21#include <unordered_set>
22
23// other includes
24#include "classdef.h"
25#include "config.h"
26#include "doxygen.h"
27#include "filedef.h"
28#include "groupdef.h"
29#include "memberdef.h"
30#include "message.h"
31#include "namespacedef.h"
32#include "portable.h"
33#include "textstream.h"
34#include "util.h"
35
37{
39 std::ofstream ntf;
41 std::ofstream ttf;
43 std::stack<bool> indentStack;
44 std::unordered_set<std::string> scopes;
45};
46
47
48DocSets::DocSets() : p(std::make_unique<Private>()) {}
49DocSets::~DocSets() = default;
50
52{
53 // -- get config options
54 DString projectName = Config_getString(PROJECT_NAME);
55 if (projectName.empty()) projectName="root";
56 DString bundleId = Config_getString(DOCSET_BUNDLE_ID);
57 if (bundleId.empty()) bundleId="org.doxygen.Project";
58 DString feedName = Config_getString(DOCSET_FEEDNAME);
59 if (feedName.empty()) feedName="FeedName";
60 DString feedURL = Config_getString(DOCSET_FEEDURL);
61 if (feedURL.empty()) feedURL="FeedUrl";
62 DString publisherId = Config_getString(DOCSET_PUBLISHER_ID);
63 if (publisherId.empty()) publisherId="PublisherId";
64 DString publisherName = Config_getString(DOCSET_PUBLISHER_NAME);
65 if (publisherName.empty()) publisherName="PublisherName";
66 DString projectNumber = Config_getString(PROJECT_NUMBER);
67 if (projectNumber.empty()) projectNumber="ProjectNumber";
68
69 // -- write Makefile
70 {
71 DString mfName = Config_getString(HTML_OUTPUT) + "/Makefile";
72 std::ofstream ts = Portable::openOutputStream(mfName);
73 if (!ts.is_open())
74 {
75 term("Could not open file {} for writing\n",mfName);
76 }
77
78 ts << "DOCSET_NAME=" << bundleId << ".docset\n"
79 "DOCSET_CONTENTS=$(DOCSET_NAME)/Contents\n"
80 "DOCSET_RESOURCES=$(DOCSET_CONTENTS)/Resources\n"
81 "DOCSET_DOCUMENTS=$(DOCSET_RESOURCES)/Documents\n"
82 "DESTDIR=~/Library/Developer/Shared/Documentation/DocSets\n"
83 "XCODE_INSTALL=\"$(shell xcode-select -print-path)\"\n"
84 "\n"
85 "all: docset\n"
86 "\n"
87 "docset:\n"
88 "\tmkdir -p $(DOCSET_DOCUMENTS)\n"
89 "\tcp Nodes.xml $(DOCSET_RESOURCES)\n"
90 "\tcp Tokens.xml $(DOCSET_RESOURCES)\n"
91 "\tcp Info.plist $(DOCSET_CONTENTS)\n"
92 "\ttar --exclude $(DOCSET_NAME) \\\n"
93 "\t --exclude Nodes.xml \\\n"
94 "\t --exclude Tokens.xml \\\n"
95 "\t --exclude Info.plist \\\n"
96 "\t --exclude Makefile -c -f - . \\\n"
97 "\t | (cd $(DOCSET_DOCUMENTS); tar xvf -)\n"
98 "\t$(XCODE_INSTALL)/usr/bin/docsetutil index $(DOCSET_NAME)\n"
99 "\trm -f $(DOCSET_DOCUMENTS)/Nodes.xml\n"
100 "\trm -f $(DOCSET_DOCUMENTS)/Info.plist\n"
101 "\trm -f $(DOCSET_DOCUMENTS)/Makefile\n"
102 "\trm -f $(DOCSET_RESOURCES)/Nodes.xml\n"
103 "\trm -f $(DOCSET_RESOURCES)/Tokens.xml\n"
104 "\n"
105 "clean:\n"
106 "\trm -rf $(DOCSET_NAME)\n"
107 "\n"
108 "install: docset\n"
109 "\tmkdir -p $(DESTDIR)\n"
110 "\tcp -R $(DOCSET_NAME) $(DESTDIR)\n"
111 "\n"
112 "uninstall:\n"
113 "\trm -rf $(DESTDIR)/$(DOCSET_NAME)\n"
114 "\n"
115 "always:\n";
116 }
117
118 // -- write Info.plist
119 {
120 DString plName = Config_getString(HTML_OUTPUT) + "/Info.plist";
121 std::ofstream ts = Portable::openOutputStream(plName);
122 if (!ts.is_open())
123 {
124 term("Could not open file {} for writing\n",plName);
125 }
126
127 ts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
128 "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\"\n"
129 "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
130 "<plist version=\"1.0\">\n"
131 "<dict>\n"
132 " <key>CFBundleName</key>\n"
133 " <string>" << projectName << "</string>\n"
134 " <key>CFBundleIdentifier</key>\n"
135 " <string>" << bundleId << "</string>\n"
136 " <key>CFBundleVersion</key>\n"
137 " <string>" << projectNumber << "</string>\n"
138 " <key>DocSetFeedName</key>\n"
139 " <string>" << feedName << "</string>\n"
140 " <key>DocSetFeedUrl</key>\n"
141 " <string>" << feedURL << "</string>\n"
142 " <key>DocSetPublisherIdentifier</key>\n"
143 " <string>" << publisherId << "</string>\n"
144 " <key>DocSetPublisherName</key>\n"
145 " <string>" << publisherName << "</string>\n"
146 // markers for Dash
147 " <key>DashDocSetFamily</key>\n"
148 " <string>doxy</string>\n"
149 " <key>DocSetPlatformFamily</key>\n"
150 " <string>doxygen</string>\n"
151 "</dict>\n"
152 "</plist>\n";
153 }
154
155 // -- start Nodes.xml
156 DString notes = Config_getString(HTML_OUTPUT) + "/Nodes.xml";
157 p->ntf = Portable::openOutputStream(notes);
158 if (!p->ntf.is_open())
159 {
160 term("Could not open file {} for writing\n",notes);
161 }
162 p->nts.setStream(&p->ntf);
163 //DString indexName=Config_getBool(GENERATE_TREEVIEW)?"main":"index";
164 DString indexName="index";
165 p->nts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
166 p->nts << "<DocSetNodes version=\"1.0\">\n";
167 p->nts << " <TOC>\n";
168 p->nts << " <Node>\n";
169 p->nts << " <Name>Root</Name>\n";
170 p->nts << " <Path>" << indexName << Doxygen::htmlFileExtension << "</Path>\n";
171 p->nts << " <Subnodes>\n";
172 p->indentStack.push(true);
173
174 DString tokens = Config_getString(HTML_OUTPUT) + "/Tokens.xml";
175 p->ttf = Portable::openOutputStream(tokens);
176 if (!p->ttf.is_open())
177 {
178 term("Could not open file {} for writing\n",tokens);
179 }
180 p->tts.setStream(&p->ttf);
181 p->tts << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
182 p->tts << "<Tokens version=\"1.0\">\n";
183}
184
186{
187 if (!p->indentStack.top())
188 {
189 p->nts << p->indent() << " </Node>\n";
190 }
191 p->indentStack.pop();
192 p->nts << " </Subnodes>\n";
193 p->nts << " </Node>\n";
194 p->nts << " </TOC>\n";
195 p->nts << "</DocSetNodes>\n";
196 p->nts.flush();
197 p->ntf.close();
198
199 p->tts << "</Tokens>\n";
200 p->tts.flush();
201 p->ttf.close();
202}
203
205{
206 DString result;
207 result.fill(' ',static_cast<int>(indentStack.size()+2)*2);
208 return result;
209}
210
212{
213 //printf("DocSets::incContentsDepth() depth=%zu\n",p->indentStack.size());
214 p->nts << p->indent() << "<Subnodes>\n";
215 p->indentStack.push(true);
216}
217
219{
220 if (!p->indentStack.top())
221 {
222 p->nts << p->indent() << " </Node>\n";
223 }
224 p->nts << p->indent() << "</Subnodes>\n";
225 p->indentStack.pop();
226 //printf("DocSets::decContentsDepth() depth=%zu\n",p->indentStack.size());
227}
228
229void DocSets::addContentsItem(bool /*isDir*/,
230 const DString &name,
231 const DString &ref,
232 const DString &file,
233 const DString &anchor,
234 bool /* separateIndex */,
235 bool /* addToNavIndex */,
236 const Definition * /*def*/,
237 const DString & /* nameAsHtml */)
238{
239 //printf("DocSets::addContentsItem(%s) depth=%zu\n",name,p->indentStack.size());
240 if (ref==nullptr)
241 {
242 if (!p->indentStack.top())
243 {
244 p->nts << p->indent() << " </Node>\n";
245 }
246 p->indentStack.top()=false;
247 p->nts << p->indent() << " <Node>\n";
248 p->nts << p->indent() << " <Name>" << convertToXML(name) << "</Name>\n";
249 if (!file.empty() && file[0]=='^') // URL marker
250 {
251 p->nts << p->indent() << " <URL>" << convertToXML(&file[1])
252 << "</URL>\n";
253 }
254 else // relative file
255 {
256 p->nts << p->indent() << " <Path>";
257 if (!file.empty() && file[0]=='!') // user specified file
258 {
259 p->nts << convertToXML(&file[1]);
260 }
261 else if (!file.empty()) // doxygen generated file
262 {
263 DString fn = file;
265 p->nts << fn;
266 }
267 p->nts << "</Path>\n";
268 if (!file.empty() && !anchor.empty())
269 {
270 p->nts << p->indent() << " <Anchor>" << anchor << "</Anchor>\n";
271 }
272 }
273 }
274}
275
276void DocSets::addIndexItem(const Definition *context,const MemberDef *md,
277 const DString &,const DString &)
278{
279 if (md==nullptr && context==nullptr) return;
280
281 const FileDef *fd = nullptr;
282 const ClassDef *cd = nullptr;
283 const NamespaceDef *nd = nullptr;
284
285 if (md)
286 {
287 fd = md->getFileDef();
288 cd = md->getClassDef();
289 nd = md->getNamespaceDef();
290 if (!md->isLinkable()) return; // internal symbol
291 }
292
293 DString scope;
294 DString type;
295 DString decl;
296
297 // determine language
298 DString lang;
299 SrcLangExt langExt = SrcLangExt::Cpp;
300 if (md)
301 {
302 langExt = md->getLanguage();
303 }
304 else if (context)
305 {
306 langExt = context->getLanguage();
307 }
308 switch (langExt)
309 {
310 case SrcLangExt::Cpp:
311 case SrcLangExt::ObjC:
312 {
313 if (md && (md->isObjCMethod() || md->isObjCProperty()))
314 lang="occ"; // Objective C/C++
315 else if (fd && fd->name().lower().endsWith(".c"))
316 lang="c"; // Plain C
317 else if (cd==nullptr && nd==nullptr)
318 lang="c"; // Plain C symbol outside any class or namespace
319 else
320 lang="cpp"; // C++
321 }
322 break;
323 case SrcLangExt::IDL: lang="idl"; break; // IDL
324 case SrcLangExt::CSharp: lang="csharp"; break; // C#
325 case SrcLangExt::PHP: lang="php"; break; // PHP4/5
326 case SrcLangExt::D: lang="d"; break; // D
327 case SrcLangExt::Java: lang="java"; break; // Java
328 case SrcLangExt::JS: lang="javascript"; break; // JavaScript
329 case SrcLangExt::Python: lang="python"; break; // Python
330 case SrcLangExt::Fortran: lang="fortran"; break; // Fortran
331 case SrcLangExt::VHDL: lang="vhdl"; break; // VHDL
332 case SrcLangExt::XML: lang="xml"; break; // DBUS XML
333 case SrcLangExt::SQL: lang="sql"; break; // Sql
334 case SrcLangExt::Markdown:lang="markdown"; break; // Markdown
335 case SrcLangExt::Slice: lang="slice"; break; // Slice
336 case SrcLangExt::Lex: lang="lex"; break; // Lex
337 case SrcLangExt::Unknown: lang="unknown"; break; // should not happen!
338 }
339
340 if (context && md)
341 {
342 switch (md->memberType())
343 {
344 case MemberType::Define:
345 type="macro"; break;
346 case MemberType::Function:
347 if (cd && (cd->compoundType()==ClassDef::Interface ||
349 {
350 if (md->isStatic())
351 type="clm"; // class member
352 else
353 type="instm"; // instance member
354 }
355 else if (cd && cd->compoundType()==ClassDef::Protocol)
356 {
357 if (md->isStatic())
358 type="intfcm"; // interface class member
359 else
360 type="intfm"; // interface member
361 }
362 else
363 type="func";
364 break;
365 case MemberType::Variable:
366 type="data"; break;
367 case MemberType::Typedef:
368 type="tdef"; break;
369 case MemberType::Enumeration:
370 type="enum"; break;
371 case MemberType::EnumValue:
372 type="econst"; break;
373 //case MemberDef::Prototype:
374 // type="prototype"; break;
375 case MemberType::Signal:
376 type="signal"; break;
377 case MemberType::Slot:
378 type="slot"; break;
379 case MemberType::Friend:
380 type="ffunc"; break;
381 case MemberType::DCOP:
382 type="dcop"; break;
383 case MemberType::Property:
384 if (cd && cd->compoundType()==ClassDef::Protocol)
385 type="intfp"; // interface property
386 else
387 type="instp"; // instance property
388 break;
389 case MemberType::Event:
390 type="event"; break;
391 case MemberType::Interface:
392 type="ifc"; break;
393 case MemberType::Service:
394 type="svc"; break;
395 case MemberType::Sequence:
396 type="sequence"; break;
397 case MemberType::Dictionary:
398 type="dictionary"; break;
399 }
400 scope = md->getScopeString();
401 fd = md->getFileDef();
402 if (fd)
403 {
404 decl = fd->name();
405 }
406 writeToken(p->tts,md,type,lang,scope,md->anchor(),decl);
407 }
408 else if (context && context->isLinkable())
409 {
410 if (fd==nullptr && context->definitionType()==Definition::TypeFile)
411 {
412 fd = toFileDef(context);
413 }
414 if (cd==nullptr && context->definitionType()==Definition::TypeClass)
415 {
416 cd = toClassDef(context);
417 }
418 if (nd==nullptr && context->definitionType()==Definition::TypeNamespace)
419 {
420 nd = toNamespaceDef(context);
421 }
422 if (fd)
423 {
424 type="file";
425 }
426 else if (cd)
427 {
428 scope = cd->qualifiedName();
429 if (cd->isTemplate())
430 {
431 type="tmplt";
432 }
433 else if (cd->compoundType()==ClassDef::Protocol)
434 {
435 type="intf";
436 if (scope.endsWith("-p")) scope=scope.left(scope.length()-2);
437 }
438 else if (cd->compoundType()==ClassDef::Interface)
439 {
440 type="cl";
441 }
442 else if (cd->compoundType()==ClassDef::Category)
443 {
444 type="cat";
445 }
446 else
447 {
448 type = "cl";
449 }
450 const IncludeInfo *ii = cd->includeInfo();
451 if (ii)
452 {
453 decl=ii->includeName;
454 }
455 }
456 else if (nd)
457 {
458 scope = nd->name();
459 type = "ns";
460 }
461 if (p->scopes.find(context->getOutputFileBase().str())==p->scopes.end())
462 {
463 writeToken(p->tts,context,type,lang,scope,DString(),decl);
464 p->scopes.insert(context->getOutputFileBase().str());
465 }
466 }
467}
468
470 const Definition *d,
471 const DString &type,
472 const DString &lang,
473 const DString &scope,
474 const DString &anchor,
475 const DString &decl)
476{
477 t << " <Token>\n";
478 t << " <TokenIdentifier>\n";
479 DString name = d->name();
480 if (name.endsWith("-p")) name=name.left(name.length()-2);
481 t << " <Name>" << convertToXML(name) << "</Name>\n";
482 if (!lang.empty())
483 {
484 t << " <APILanguage>" << lang << "</APILanguage>\n";
485 }
486 if (!type.empty())
487 {
488 t << " <Type>" << type << "</Type>\n";
489 }
490 if (!scope.empty())
491 {
492 t << " <Scope>" << convertToXML(scope) << "</Scope>\n";
493 }
494 t << " </TokenIdentifier>\n";
495 DString fn = d->getOutputFileBase();
497 t << " <Path>" << fn << "</Path>\n";
498 if (!anchor.empty())
499 {
500 t << " <Anchor>" << anchor << "</Anchor>\n";
501 }
502 DString tooltip = d->briefDescriptionAsTooltip();
503 if (!tooltip.empty())
504 {
505 t << " <Abstract>" << convertToXML(tooltip) << "</Abstract>\n";
506 }
507 if (!decl.empty())
508 {
509 t << " <DeclaredIn>" << convertToXML(decl) << "</DeclaredIn>\n";
510 }
511 t << " </Token>\n";
512}
513
514void DocSets::addIndexFile(const DString &/*name*/)
515{
516}
517
A abstract class representing of a compound symbol.
Definition classdef.h:100
virtual bool isTemplate() const =0
Returns true if this class is a template.
@ Interface
Definition classdef.h:108
virtual CompoundType compoundType() const =0
Returns the type of compound this is, i.e. class/struct/union/...
virtual const IncludeInfo * includeInfo() const =0
A String class for use with Doxygen wrapping std::string and adding some additional functionality off...
Definition dstring.h:84
DString fill(char c, size_t len)
Fills a string with a predefined character.
Definition dstring.h:278
DString lower() const
Definition dstring.h:326
bool empty() const
Returns true iff the string is empty (std::string compatible alias for isEmpty()).
Definition dstring.h:148
DString left(size_t len) const
Definition dstring.h:306
const std::string & str() const
Definition dstring.h:645
bool endsWith(const char *s) const
Definition dstring.h:617
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition dstring.h:151
The common base class of all entity definitions found in the sources.
Definition definition.h:77
virtual SrcLangExt getLanguage() const =0
Returns the programming language this definition was written in.
virtual bool isLinkable() const =0
virtual DefType definitionType() const =0
virtual const DString & name() const =0
virtual DString briefDescriptionAsTooltip() const =0
virtual DString qualifiedName() const =0
virtual DString anchor() const =0
virtual DString getOutputFileBase() const =0
void decContentsDepth()
Definition docsets.cpp:218
void addContentsItem(bool isDir, const DString &name, const DString &ref, const DString &file, const DString &anchor, bool separateIndex, bool addToNavIndex, const Definition *def, const DString &nameAsHtml)
Definition docsets.cpp:229
void incContentsDepth()
Definition docsets.cpp:211
void addIndexFile(const DString &name)
Definition docsets.cpp:514
std::unique_ptr< Private > p
Definition docsets.h:67
void addIndexItem(const Definition *context, const MemberDef *md, const DString &sectionAnchor, const DString &title)
Definition docsets.cpp:276
void writeToken(TextStream &t, const Definition *d, const DString &type, const DString &lang, const DString &scope=DString(), const DString &anchor=DString(), const DString &decl=DString())
Definition docsets.cpp:469
void initialize()
Definition docsets.cpp:51
void finalize()
Definition docsets.cpp:185
DocSets()
Definition docsets.cpp:48
static DString htmlFileExtension
Definition doxygen.h:115
A model of a file symbol.
Definition filedef.h:97
Class representing the data associated with a #include statement.
Definition filedef.h:72
DString includeName
Definition filedef.h:78
A model of a class/file/namespace member symbol.
Definition memberdef.h:45
virtual bool isObjCMethod() const =0
virtual const ClassDef * getClassDef() const =0
virtual const FileDef * getFileDef() const =0
virtual bool isStatic() const =0
virtual const NamespaceDef * getNamespaceDef() const =0
virtual DString getScopeString() const =0
virtual bool isObjCProperty() const =0
virtual MemberType memberType() const =0
An abstract interface of a namespace symbol.
Text streaming class that buffers data.
Definition textstream.h:36
ClassDef * toClassDef(Definition *d)
#define Config_getString(name)
Definition config.h:32
FileDef * toFileDef(Definition *d)
Definition filedef.cpp:1973
#define term(fmt,...)
Definition message.h:137
std::ofstream openOutputStream(const DString &name, bool append=false)
Definition portable.cpp:681
NamespaceDef * toNamespaceDef(Definition *d)
Definition dstring.h:913
Portable versions of functions that are platform dependent.
std::ofstream ttf
Definition docsets.cpp:41
std::unordered_set< std::string > scopes
Definition docsets.cpp:44
TextStream nts
Definition docsets.cpp:40
TextStream tts
Definition docsets.cpp:42
std::ofstream ntf
Definition docsets.cpp:39
std::stack< bool > indentStack
Definition docsets.cpp:43
DString indent()
Definition docsets.cpp:204
SrcLangExt
Definition types.h:207
void addHtmlExtensionIfMissing(DString &fName)
Definition util.cpp:3931
DString convertToXML(const DString &s, bool keepEntities, const bool citeEntry)
Definition util.cpp:3232
A bunch of utility functions.