Doxygen
Loading...
Searching...
No Matches
dot.cpp
Go to the documentation of this file.
1/*****************************************************************************
2 *
3 * Copyright (C) 1997-2019 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 <cstdlib>
17#include <cassert>
18#include <sstream>
19#include <algorithm>
20#include <mutex>
21
22#include "config.h"
23#include "dot.h"
24#include "dotrunner.h"
25#include "dotfilepatcher.h"
26#include "util.h"
27#include "portable.h"
28#include "message.h"
29#include "doxygen.h"
30#include "language.h"
31#include "indexlist.h"
32#include "dir.h"
33
34#define MAP_CMD "cmapx"
35
36//--------------------------------------------------------------------
37
39
40static std::mutex g_dotManagerMutex;
41
42static void setDotFontPath(const QCString &path)
43{
44 ASSERT(g_dotFontPath.isEmpty());
45 g_dotFontPath = Portable::getenv("DOTFONTPATH");
46 QCString newFontPath = Config_getString(DOT_FONTPATH);
47 if (!newFontPath.isEmpty() && !path.isEmpty())
48 {
49 newFontPath.prepend(path+Portable::pathListSeparator());
50 }
51 else if (newFontPath.isEmpty() && !path.isEmpty())
52 {
53 newFontPath=path;
54 }
55 else
56 {
57 Portable::unsetenv("DOTFONTPATH");
58 return;
59 }
60 Portable::setenv("DOTFONTPATH",newFontPath);
61}
62
63static void unsetDotFontPath()
64{
65 if (g_dotFontPath.isEmpty())
66 {
67 Portable::unsetenv("DOTFONTPATH");
68 }
69 else
70 {
71 Portable::setenv("DOTFONTPATH",g_dotFontPath);
72 }
74}
75
76//--------------------------------------------------------------------
77
79{
80 static DotManager theInstance;
81 return &theInstance;
82}
83
87
91
92void DotManager::addJob(const DotJob &newJob)
93{
94 std::lock_guard<std::mutex> lock(g_dotManagerMutex);
95 for (const auto &job : m_jobs)
96 {
97 if (job.absPath == newJob.absPath && job.relDotName == newJob.relDotName && job.format == newJob.format) return; // already queued
98 if (job.absPath == newJob.absPath && job.relDotName == newJob.relDotName && job.md5Hash != newJob.md5Hash)
99 {
100 err("md5 hash does not match for two different runs of {}{} !\n", newJob.absPath, newJob.relDotName);
101 return;
102 }
103 }
104 m_jobs.push_back(newJob);
105}
106
108{
109 std::lock_guard<std::mutex> lock(g_dotManagerMutex);
110 auto patcher = m_filePatchers.find(fileName.str());
111
112 if (patcher != m_filePatchers.end()) return &(patcher->second);
113
114 auto rv = m_filePatchers.emplace(fileName.str(), fileName);
115 assert(rv.second);
116 return &(rv.first->second);
117}
118
120{
121 size_t numFilePatchers = m_filePatchers.size();
122 if (m_jobs.size()+numFilePatchers > 0)
123 {
124 if (Config_getInt(DOT_NUM_THREADS)<=1)
125 {
126 msg("Generating {:d} dot graphs in single threaded mode with batch size {:d}...\n",
127 m_jobs.size(),Config_getInt(DOT_BATCH_SIZE));
128 }
129 else
130 {
131 msg("Generating {:d} dot graphs using {:d} parallel threads with batch size {:d}...\n",
132 m_jobs.size(),Config_getInt(DOT_NUM_THREADS),Config_getInt(DOT_BATCH_SIZE));
133 }
134 }
135
136 bool setPath=FALSE;
137 if (Config_getBool(GENERATE_HTML))
138 {
139 setDotFontPath(Config_getString(HTML_OUTPUT));
140 setPath=TRUE;
141 }
142 else if (Config_getBool(GENERATE_LATEX))
143 {
144 setDotFontPath(Config_getString(LATEX_OUTPUT));
145 setPath=TRUE;
146 }
147 else if (Config_getBool(GENERATE_RTF))
148 {
149 setDotFontPath(Config_getString(RTF_OUTPUT));
150 setPath=TRUE;
151 }
152 else if (Config_getBool(GENERATE_DOCBOOK))
153 {
154 setDotFontPath(Config_getString(DOCBOOK_OUTPUT));
155 setPath=TRUE;
156 }
157
158 bool ok = m_runner.run(m_jobs);
159
160 if (setPath)
161 {
163 }
164
165 if (!ok) return FALSE;
166
167 // patch the output file and insert the maps and figures
168 size_t i=1;
169 // since patching the svg files may involve patching the header of the SVG
170 // (for zoomable SVGs), and patching the .html files requires reading that
171 // header after the SVG is patched, we first process the .svg files and
172 // then the other files.
173 for (auto & fp : m_filePatchers)
174 {
175 if (fp.second.isSVGFile())
176 {
177 msg("Patching output file {}/{}\n",i,numFilePatchers);
178 if (!fp.second.run()) return FALSE;
179 i++;
180 }
181 }
182 for (auto& fp : m_filePatchers)
183 {
184 if (!fp.second.isSVGFile())
185 {
186 msg("Patching output file {}/{}\n",i,numFilePatchers);
187 if (!fp.second.run()) return FALSE;
188 i++;
189 }
190 }
191 return TRUE;
192}
193
194//--------------------------------------------------------------------
195
196void writeDotGraphFromFile(const QCString &inFile,const QCString &outDir,
197 const QCString &outFile,GraphOutputFormat format,
198 const QCString &srcFile,int srcLine,bool toIndex)
199{
200 Dir d(outDir.str());
201 if (!d.exists())
202 {
203 term("Output dir {} does not exist!\n",outDir);
204 }
205
207 QCString imgName = outFile+"."+imgExt;
208 QCString absImgName = d.absPath()+"/"+imgName;
209 QCString absOutFile = d.absPath()+"/"+outFile;
210
211 QCString dotArgs;
212 if (format==GraphOutputFormat::BITMAP)
213 {
214 dotArgs = QCString("-T") + Config_getEnumAsString(DOT_IMAGE_FORMAT) + " -o \"" + absImgName + "\" \"" + inFile + "\"";
215 }
216 else // format==GraphOutputFormat::EPS
217 {
218 if (Config_getBool(USE_PDFLATEX))
219 {
220 dotArgs = QCString("-Tpdf -o \"") + absOutFile + ".pdf\" \"" + inFile + "\"";
221 }
222 else
223 {
224 dotArgs = QCString("-Teps -o \"") + absOutFile + ".eps\" \"" + inFile + "\"";
225 }
226 }
227
229 {
230 return;
231 }
232
233 if (toIndex) Doxygen::indexList->addImageFile(imgName);
234
235}
236
237/*! Writes user defined image map to the output.
238 * \param t text stream to write to
239 * \param inFile just the basename part of the filename
240 * \param outDir output directory
241 * \param relPath relative path the to root of the output dir
242 * \param baseName the base name of the output files
243 * \param context the scope in which this graph is found (for resolving links)
244 * \param graphId a unique id for this graph, use for dynamic sections
245 * \param srcFile the source file
246 * \param srcLine the line number in the source file
247 * \param newFile signal whether or not the file has been generated before (value `false`) or not.
248 */
250 const QCString &inFile, const QCString &outDir,
251 const QCString &relPath, const QCString &baseName,
252 const QCString &context,int graphId,
253 const QCString &srcFile,int srcLine, bool newFile)
254{
255
256 Dir d(outDir.str());
257 if (!d.exists())
258 {
259 term("Output dir {} does not exist!\n",outDir);
260 }
261
262 QCString mapName = baseName+".cmapx";
264 QCString imgName = baseName+"."+imgExt;
265 QCString absOutFile = d.absPath()+"/"+mapName;
266
267 QCString dotArgs = QCString("-T" MAP_CMD " -o \"") + absOutFile + "\" \"" + inFile + "\"";
269 {
270 return;
271 }
272
273 if (imgExt=="svg") // vector graphics
274 {
275 QCString svgName = outDir+"/"+baseName+".svg";
276 DotFilePatcher::writeSVGFigureLink(t,relPath,baseName,svgName);
277 if (newFile)
278 {
279 DotFilePatcher patcher(svgName);
280 patcher.addSVGConversion("",TRUE,context,TRUE,graphId);
281 patcher.run();
282 }
283 }
284 else // bitmap graphics
285 {
286 TextStream tt;
287 t << "<img src=\"" << relPath << imgName << "\" alt=\""
288 << imgName << "\" border=\"0\" usemap=\"#" << mapName << "\"/>\n";
289 DotFilePatcher::convertMapFile(tt, absOutFile, relPath ,TRUE, context);
290 if (!tt.empty())
291 {
292 t << "<map name=\"" << mapName << "\" id=\"" << mapName << "\">";
293 t << tt.str();
294 t << "</map>\n";
295 }
296 }
297 d.remove(absOutFile.str());
298}
Class representing a directory in the file system.
Definition dir.h:75
std::string absPath() const
Definition dir.cpp:364
bool remove(const std::string &path, bool acceptsAbsPath=true) const
Definition dir.cpp:314
bool exists() const
Definition dir.cpp:257
Helper class to insert a set of map file into an output file.
static bool convertMapFile(TextStream &t, const QCString &mapName, const QCString &relPath, bool urlOnly=FALSE, const QCString &context=QCString())
int addSVGConversion(const QCString &relPath, bool urlOnly, const QCString &context, bool zoomable, int graphId)
static bool writeSVGFigureLink(TextStream &out, const QCString &relPath, const QCString &baseName, const QCString &absImgName)
Check if a reference to a SVG figure can be written and do so if possible.
DotManager()
Definition dot.cpp:84
std::map< std::string, DotFilePatcher > m_filePatchers
Definition dot.h:47
DotFilePatcher * createFilePatcher(const QCString &fileName)
Definition dot.cpp:107
void addJob(const DotJob &newJob)
Definition dot.cpp:92
DotJobs m_jobs
Definition dot.h:48
bool run()
Definition dot.cpp:119
DotRunner m_runner
Definition dot.h:46
virtual ~DotManager()
Definition dot.cpp:88
static DotManager * instance()
Definition dot.cpp:78
static QCString verifiedDotPath
Definition doxygen.h:137
static IndexList * indexList
Definition doxygen.h:132
This is an alternative implementation of QCString.
Definition qcstring.h:101
QCString & prepend(const char *s)
Definition qcstring.h:422
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:163
const std::string & str() const
Definition qcstring.h:552
Text streaming class that buffers data.
Definition textstream.h:36
bool empty() const
Returns true iff the buffer is empty.
Definition textstream.h:240
std::string str() const
Return the contents of the buffer as a std::string object.
Definition textstream.h:216
#define Config_getInt(name)
Definition config.h:34
#define Config_getEnumAsString(name)
Definition config.h:36
#define Config_getBool(name)
Definition config.h:33
#define Config_getString(name)
Definition config.h:32
static void setDotFontPath(const QCString &path)
Definition dot.cpp:42
static QCString g_dotFontPath
Definition dot.cpp:38
static void unsetDotFontPath()
Definition dot.cpp:63
#define MAP_CMD
Definition dot.cpp:34
void writeDotGraphFromFile(const QCString &inFile, const QCString &outDir, const QCString &outFile, GraphOutputFormat format, const QCString &srcFile, int srcLine, bool toIndex)
Definition dot.cpp:196
static std::mutex g_dotManagerMutex
Definition dot.cpp:40
void writeDotImageMapFromFile(TextStream &t, const QCString &inFile, const QCString &outDir, const QCString &relPath, const QCString &baseName, const QCString &context, int graphId, const QCString &srcFile, int srcLine, bool newFile)
Definition dot.cpp:249
GraphOutputFormat
Definition dotgraph.h:29
#define msg(fmt,...)
Definition message.h:94
#define err(fmt,...)
Definition message.h:127
#define term(fmt,...)
Definition message.h:137
QCString pathListSeparator()
Definition portable.cpp:383
int system(const QCString &command, const QCString &args, bool commandHasConsole=true)
Definition portable.cpp:105
void setenv(const QCString &variable, const QCString &value)
Definition portable.cpp:286
void unsetenv(const QCString &variable)
Definition portable.cpp:301
QCString getenv(const QCString &variable)
Definition portable.cpp:321
Portable versions of functions that are platform dependent.
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34
#define ASSERT(x)
Definition qcstring.h:39
QCString md5Hash
Definition dotjob.h:30
QCString format
Definition dotjob.h:29
QCString relDotName
Definition dotjob.h:28
QCString absPath
Definition dotjob.h:27
QCString getDotImageExtension()
Definition util.cpp:6307
A bunch of utility functions.