Skip to content

Commit df273ec

Browse files
albert-githubdoxygen
authored andcommitted
issue doxygen#11492 @plantumlfile command not recognized
- The original problem is about the fact that fact that the `@startuml` command had a filename and this was not expected / anticipated, the result was a concatenation of the name with and "inline" name (i.e. an generated dummy name) and the given name - Potential problem with handing out the same number for an "inline" file name (multithreading, now protected by means of a mutex. - With a `\plantumlfile` it is possible to have multiple diagrams in one file, only one was shown, now all are shown.
1 parent 5e717bf commit df273ec

File tree

7 files changed

+222
-89
lines changed

7 files changed

+222
-89
lines changed

src/docbookvisitor.cpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -433,13 +433,16 @@ DB_VIS_C
433433
case DocVerbatim::PlantUML:
434434
{
435435
QCString docbookOutput = Config_getString(DOCBOOK_OUTPUT);
436-
QCString baseName = PlantumlManager::instance().writePlantUMLSource(docbookOutput,
436+
std::vector<QCString> baseNameVector = PlantumlManager::instance().writePlantUMLSource(docbookOutput,
437437
s.exampleFile(),s.text(),PlantumlManager::PUML_BITMAP,
438438
s.engine(),s.srcFile(),s.srcLine(),true);
439-
QCString shortName = makeShortName(baseName);
440-
m_t << "<para>\n";
441-
writePlantUMLFile(baseName,s);
442-
m_t << "</para>\n";
439+
for(const auto &baseName: baseNameVector)
440+
{
441+
QCString shortName = makeShortName(baseName);
442+
m_t << "<para>\n";
443+
writePlantUMLFile(baseName,s);
444+
m_t << "</para>\n";
445+
}
443446
}
444447
break;
445448
}
@@ -1577,12 +1580,18 @@ DB_VIS_C
15771580
QCString outDir = Config_getString(DOCBOOK_OUTPUT);
15781581
std::string inBuf;
15791582
readInputFile(fileName,inBuf);
1580-
QCString baseName = PlantumlManager::instance().writePlantUMLSource(outDir,
1583+
std::vector<QCString> baseNameVector = PlantumlManager::instance().writePlantUMLSource(outDir,
15811584
QCString(),inBuf.c_str(),PlantumlManager::PUML_BITMAP,QCString(),srcFile,srcLine,false);
1582-
baseName=makeBaseName(baseName);
1583-
PlantumlManager::instance().generatePlantUMLOutput(baseName,outDir,PlantumlManager::PUML_BITMAP);
1584-
m_t << "<para>\n";
1585-
visitPreStart(m_t, children, hasCaption, relPath + baseName + ".png", width, height);
1585+
bool first = true;
1586+
for(auto &baseName: baseNameVector)
1587+
{
1588+
baseName=makeBaseName(baseName);
1589+
PlantumlManager::instance().generatePlantUMLOutput(baseName,outDir,PlantumlManager::PUML_BITMAP);
1590+
if (!first) endPlantUmlFile(hasCaption);
1591+
first = false;
1592+
m_t << "<para>\n";
1593+
visitPreStart(m_t, children, hasCaption, relPath + baseName + ".png", width, height);
1594+
}
15861595
}
15871596

15881597
void DocbookDocVisitor::endPlantUmlFile(bool hasCaption)

src/htmldocvisitor.cpp

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -690,13 +690,16 @@ void HtmlDocVisitor::operator()(const DocVerbatim &s)
690690
{
691691
format = PlantumlManager::PUML_SVG;
692692
}
693-
QCString baseName = PlantumlManager::instance().writePlantUMLSource(
693+
std::vector<QCString> baseNameVector = PlantumlManager::instance().writePlantUMLSource(
694694
htmlOutput,s.exampleFile(),
695695
s.text(),format,s.engine(),s.srcFile(),s.srcLine(),true);
696-
m_t << "<div class=\"plantumlgraph\">\n";
697-
writePlantUMLFile(baseName,s.relPath(),s.context(),s.srcFile(),s.srcLine());
698-
visitCaption(m_t, s);
699-
m_t << "</div>\n";
696+
for(const auto &baseName: baseNameVector)
697+
{
698+
m_t << "<div class=\"plantumlgraph\">\n";
699+
writePlantUMLFile(baseName,s.relPath(),s.context(),s.srcFile(),s.srcLine());
700+
visitCaption(m_t, s);
701+
m_t << "</div>\n";
702+
}
700703
forceStartParagraph(s);
701704
}
702705
break;
@@ -1849,22 +1852,25 @@ void HtmlDocVisitor::operator()(const DocPlantUmlFile &df)
18491852
}
18501853
std::string inBuf;
18511854
readInputFile(df.file(),inBuf);
1852-
QCString baseName = PlantumlManager::instance().writePlantUMLSource(
1855+
std::vector<QCString> baseNameVector = PlantumlManager::instance().writePlantUMLSource(
18531856
htmlOutput,QCString(),
18541857
inBuf.c_str(),format,QCString(),df.srcFile(),df.srcLine(),false);
1855-
baseName=makeBaseName(baseName);
1856-
m_t << "<div class=\"plantumlgraph\">\n";
1857-
writePlantUMLFile(baseName,df.relPath(),QCString(),df.srcFile(),df.srcLine());
1858-
if (df.hasCaption())
1859-
{
1860-
m_t << "<div class=\"caption\">\n";
1861-
}
1862-
visitChildren(df);
1863-
if (df.hasCaption())
1858+
for(auto &baseName: baseNameVector)
18641859
{
1860+
baseName=makeBaseName(baseName);
1861+
m_t << "<div class=\"plantumlgraph\">\n";
1862+
writePlantUMLFile(baseName,df.relPath(),QCString(),df.srcFile(),df.srcLine());
1863+
if (df.hasCaption())
1864+
{
1865+
m_t << "<div class=\"caption\">\n";
1866+
}
1867+
visitChildren(df);
1868+
if (df.hasCaption())
1869+
{
1870+
m_t << "</div>\n";
1871+
}
18651872
m_t << "</div>\n";
18661873
}
1867-
m_t << "</div>\n";
18681874
forceStartParagraph(df);
18691875
}
18701876

src/latexdocvisitor.cpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -550,12 +550,15 @@ void LatexDocVisitor::operator()(const DocVerbatim &s)
550550
case DocVerbatim::PlantUML:
551551
{
552552
QCString latexOutput = Config_getString(LATEX_OUTPUT);
553-
QCString baseName = PlantumlManager::instance().writePlantUMLSource(
553+
std::vector<QCString> baseNameVector = PlantumlManager::instance().writePlantUMLSource(
554554
latexOutput,s.exampleFile(),s.text(),
555555
s.useBitmap() ? PlantumlManager::PUML_BITMAP : PlantumlManager::PUML_EPS,
556556
s.engine(),s.srcFile(),s.srcLine(),true);
557557

558-
writePlantUMLFile(baseName, s);
558+
for(const auto &baseName: baseNameVector)
559+
{
560+
writePlantUMLFile(baseName, s);
561+
}
559562
}
560563
break;
561564
}
@@ -2119,19 +2122,25 @@ void LatexDocVisitor::startPlantUmlFile(const QCString &fileName,
21192122
readInputFile(fileName,inBuf);
21202123

21212124
bool useBitmap = inBuf.find("@startditaa") != std::string::npos;
2122-
QCString baseName = PlantumlManager::instance().writePlantUMLSource(
2125+
std::vector<QCString> baseNameVector = PlantumlManager::instance().writePlantUMLSource(
21232126
outDir,QCString(),inBuf.c_str(),
21242127
useBitmap ? PlantumlManager::PUML_BITMAP : PlantumlManager::PUML_EPS,
21252128
QCString(),srcFile,srcLine,false);
2126-
baseName=makeBaseName(baseName);
2127-
QCString shortName = makeShortName(baseName);
2128-
if (useBitmap)
2129+
bool first = true;
2130+
for(auto &baseName: baseNameVector)
21292131
{
2130-
if (shortName.find('.')==-1) shortName += ".png";
2132+
baseName=makeBaseName(baseName);
2133+
QCString shortName = makeShortName(baseName);
2134+
if (useBitmap)
2135+
{
2136+
if (shortName.find('.')==-1) shortName += ".png";
2137+
}
2138+
PlantumlManager::instance().generatePlantUMLOutput(baseName,outDir,
2139+
useBitmap ? PlantumlManager::PUML_BITMAP : PlantumlManager::PUML_EPS);
2140+
if (!first) endPlantUmlFile(hasCaption);
2141+
first = false;
2142+
visitPreStart(m_t,hasCaption, shortName, width, height);
21312143
}
2132-
PlantumlManager::instance().generatePlantUMLOutput(baseName,outDir,
2133-
useBitmap ? PlantumlManager::PUML_BITMAP : PlantumlManager::PUML_EPS);
2134-
visitPreStart(m_t,hasCaption, shortName, width, height);
21352144
}
21362145

21372146
void LatexDocVisitor::endPlantUmlFile(bool hasCaption)

src/plantuml.cpp

Lines changed: 138 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
*
1414
*/
1515

16+
#include <mutex>
1617
#include "plantuml.h"
1718
#include "util.h"
1819
#include "portable.h"
@@ -25,15 +26,17 @@
2526
#include "indexlist.h"
2627
#include "stringutil.h"
2728

28-
QCString PlantumlManager::writePlantUMLSource(const QCString &outDirArg,const QCString &fileName,
29+
static std::mutex g_PlantUmlMutex;
30+
31+
std::vector<QCString> PlantumlManager::writePlantUMLSource(const QCString &outDirArg,const QCString &fileName,
2932
const QCString &content,OutputFormat format, const QCString &engine,
3033
const QCString &srcFile,int srcLine,bool inlineCode)
3134
{
35+
std::vector<QCString> baseNameVector;
3236
QCString baseName;
3337
QCString puName;
3438
QCString imgName;
3539
QCString outDir(outDirArg);
36-
static int umlindex=1;
3740

3841
Debug::print(Debug::Plantuml,0,"*** writePlantUMLSource fileName: {}\n",fileName);
3942
Debug::print(Debug::Plantuml,0,"*** writePlantUMLSource outDir: {}\n",outDir);
@@ -45,32 +48,7 @@ QCString PlantumlManager::writePlantUMLSource(const QCString &outDirArg,const QC
4548
outDir = outDir.left(l-1);
4649
}
4750

48-
if (fileName.isEmpty()) // generate name
49-
{
50-
puName = "inline_umlgraph_"+QCString().setNum(umlindex);
51-
baseName = outDir+"/inline_umlgraph_"+QCString().setNum(umlindex++);
52-
}
53-
else // user specified name
54-
{
55-
baseName = fileName;
56-
int i=baseName.findRev('.');
57-
if (i!=-1) baseName = baseName.left(i);
58-
puName = baseName;
59-
baseName.prepend(outDir+"/");
60-
}
61-
62-
switch (format)
63-
{
64-
case PUML_BITMAP:
65-
imgName =puName+".png";
66-
break;
67-
case PUML_EPS:
68-
imgName =puName+".eps";
69-
break;
70-
case PUML_SVG:
71-
imgName =puName+".svg";
72-
break;
73-
}
51+
generatePlantUmlFileNames(fileName,format,outDir,baseName,puName,imgName);
7452

7553
Debug::print(Debug::Plantuml,0,"*** writePlantUMLSourcebaseName: {}\n",baseName);
7654
Debug::print(Debug::Plantuml,0,"*** writePlantUMLSourcebaseName puName: {}\n",puName);
@@ -84,7 +62,7 @@ QCString PlantumlManager::writePlantUMLSource(const QCString &outDirArg,const QC
8462
{
8563
char c = 0;
8664
bool insideComment = false;
87-
bool initial = true;
65+
QCString locEngine;
8866
while ((c=*p++))
8967
{
9068
text+=c;
@@ -95,34 +73,153 @@ QCString PlantumlManager::writePlantUMLSource(const QCString &outDirArg,const QC
9573
case '\t': break;
9674
case ' ': break;
9775
case '@':
98-
if (initial && literal_at(p,"start")) // @start...
76+
if (!insideComment && literal_at(p,"start")) // @start...
9977
{
100-
while ((c=*p++) && isId(c)) text+=c;
78+
locEngine.clear();
79+
p+=5;
80+
text += "start";
81+
while ((c=*p++) && isId(c))
82+
{
83+
locEngine += c;
84+
text+=c;
85+
}
86+
QCString line;
87+
// get everything till end or endOfLine
88+
if (c && (c!='\n'))
89+
{
90+
line += c;
91+
while ((c=*p++) && (c!='\n')) line+=c;
92+
line = line.stripWhiteSpace();
93+
}
94+
QCString inpName;
95+
QCString rest;
96+
// REGEXP (<fn>)(<ext>?)(<rest>)
97+
static const reg::Ex re_new0(R"((([A-Za-z0-9_][A-Za-z0-9_-]*)))");
98+
static const reg::Ex re_new1(R"((([A-Za-z0-9_][A-Za-z0-9_-]*)(\.[A-Za-z0-9_][A-Za-z0-9_-]*)))");
99+
static const reg::Ex re_new2(R"((([A-Za-z0-9_][A-Za-z0-9_-]*)(\.[A-Za-z0-9_][A-Za-z0-9_-]*)(.*)))");
100+
static const reg::Ex re_new3(R"(([A-Za-z0-9_][A-Za-z0-9_-]*)(.*))");
101+
//std::string_view txtStr = line.view();
102+
if (!line.isEmpty())
103+
{
104+
reg::Match match0;
105+
reg::Match match1;
106+
reg::Match match2;
107+
reg::Match match3;
108+
bool matchSet = false;
109+
if (matchSet = reg::match(line.str(),match0,re_new0))
110+
{
111+
inpName = match0[1].str();
112+
}
113+
else if (matchSet = reg::match(line.str(),match1,re_new1))
114+
{
115+
inpName = match1[1].str();
116+
}
117+
else if (matchSet = reg::match(line.str(),match2,re_new2))
118+
{
119+
inpName = match2[1].str();
120+
rest = match2[3].str();
121+
}
122+
else if (matchSet = reg::match(line.str(),match3,re_new3))
123+
{
124+
inpName = match3[1].str();
125+
rest = match3[2].str();
126+
}
127+
if (matchSet)
128+
{
129+
generatePlantUmlFileNames(inpName,format,outDir,baseName,puName,imgName);
130+
}
131+
else
132+
{
133+
generatePlantUmlFileNames(QCString(),format,outDir,baseName,puName,imgName);
134+
}
135+
}
136+
else
137+
{
138+
generatePlantUmlFileNames(QCString(),format,outDir,baseName,puName,imgName);
139+
}
140+
101141
// insert the image name
102142
text+=' ';
103143
text+=imgName;
144+
145+
if (!rest.isEmpty())
146+
{
147+
text += '\n';
148+
text += rest;
149+
}
104150
if (c) text+=c;
105151
}
152+
else if (!insideComment && strncmp(p,("end"+locEngine).data(), 3+strlen(engine.data()))==0) // @end...
153+
{
154+
text += "end"+locEngine+"\n";
155+
p+=3+locEngine.length();
156+
if (!inlineCode)
157+
{
158+
QCString qcOutDir(substitute(outDir,"\\","/"));
159+
uint32_t pos = qcOutDir.findRev("/");
160+
QCString generateType(qcOutDir.right(qcOutDir.length() - (pos + 1)) );
161+
Debug::print(Debug::Plantuml,0,"*** writePlantUMLSource generateType: {}\n",generateType);
162+
PlantumlManager::instance().insert(generateType.str(),puName.str(),outDir,format,text,srcFile,srcLine);
163+
Debug::print(Debug::Plantuml,0,"*** writePlantUMLSource generateType: {}\n",generateType);
164+
baseNameVector.emplace_back(baseName);
165+
text.clear();
166+
}
167+
}
106168
break;
107169
default:
108-
if (!insideComment) initial=false;
109170
break;
110171
}
111172
}
112173
text+='\n';
113174
}
114-
if (inlineCode) text +="@end"+engine+"\n";
175+
if (inlineCode)
176+
{
177+
text +="@end"+engine+"\n";
178+
//printf("content\n====\n%s\n=====\n->\n-----\n%s\n------\n",qPrint(content),qPrint(text));
179+
QCString qcOutDir(substitute(outDir,"\\","/"));
180+
uint32_t pos = qcOutDir.findRev("/");
181+
QCString generateType(qcOutDir.right(qcOutDir.length() - (pos + 1)) );
182+
Debug::print(Debug::Plantuml,0,"*** writePlantUMLSource generateType: {}\n",generateType);
183+
PlantumlManager::instance().insert(generateType.str(),puName.str(),outDir,format,text,srcFile,srcLine);
184+
Debug::print(Debug::Plantuml,0,"*** writePlantUMLSource generateType: {}\n",generateType);
185+
baseNameVector.emplace_back(baseName);
186+
}
115187

116-
//printf("content\n====\n%s\n=====\n->\n-----\n%s\n------\n",qPrint(content),qPrint(text));
188+
return baseNameVector;
189+
}
117190

118-
QCString qcOutDir(substitute(outDir,"\\","/"));
119-
uint32_t pos = qcOutDir.findRev("/");
120-
QCString generateType(qcOutDir.right(qcOutDir.length() - (pos + 1)) );
121-
Debug::print(Debug::Plantuml,0,"*** writePlantUMLSource generateType: {}\n",generateType);
122-
PlantumlManager::instance().insert(generateType.str(),puName.str(),outDir,format,text,srcFile,srcLine);
123-
Debug::print(Debug::Plantuml,0,"*** writePlantUMLSource generateType: {}\n",generateType);
191+
void PlantumlManager::generatePlantUmlFileNames(const QCString &fileName,OutputFormat format,const QCString &outDir,
192+
QCString &baseName,QCString &puName,QCString &imgName)
193+
{
194+
static int umlindex=1;
195+
196+
if (fileName.isEmpty()) // generate name
197+
{
198+
std::lock_guard<std::mutex> lock(g_PlantUmlMutex);
199+
puName = "inline_umlgraph_"+QCString().setNum(umlindex);
200+
baseName = outDir+"/inline_umlgraph_"+QCString().setNum(umlindex++);
201+
}
202+
else // user specified name
203+
{
204+
baseName = fileName;
205+
int i=baseName.findRev('.');
206+
if (i!=-1) baseName = baseName.left(i);
207+
puName = baseName;
208+
baseName.prepend(outDir+"/");
209+
}
124210

125-
return baseName;
211+
switch (format)
212+
{
213+
case PUML_BITMAP:
214+
imgName =puName+".png";
215+
break;
216+
case PUML_EPS:
217+
imgName =puName+".eps";
218+
break;
219+
case PUML_SVG:
220+
imgName =puName+".svg";
221+
break;
222+
}
126223
}
127224

128225
void PlantumlManager::generatePlantUMLOutput(const QCString &baseName,const QCString &/* outDir */,OutputFormat format)

0 commit comments

Comments
 (0)