Skip to content

Commit c4189cf

Browse files
committed
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 b4437b3 commit c4189cf

7 files changed

+222
-89
lines changed

src/docbookvisitor.cpp

+19-10
Original file line numberDiff line numberDiff line change
@@ -431,13 +431,16 @@ DB_VIS_C
431431
case DocVerbatim::PlantUML:
432432
{
433433
QCString docbookOutput = Config_getString(DOCBOOK_OUTPUT);
434-
QCString baseName = PlantumlManager::instance().writePlantUMLSource(docbookOutput,
434+
std::vector<QCString> baseNameVector = PlantumlManager::instance().writePlantUMLSource(docbookOutput,
435435
s.exampleFile(),s.text(),PlantumlManager::PUML_BITMAP,
436436
s.engine(),s.srcFile(),s.srcLine(),true);
437-
QCString shortName = makeShortName(baseName);
438-
m_t << "<para>\n";
439-
writePlantUMLFile(baseName,s);
440-
m_t << "</para>\n";
437+
for(const auto &baseName: baseNameVector)
438+
{
439+
QCString shortName = makeShortName(baseName);
440+
m_t << "<para>\n";
441+
writePlantUMLFile(baseName,s);
442+
m_t << "</para>\n";
443+
}
441444
}
442445
break;
443446
}
@@ -1561,12 +1564,18 @@ DB_VIS_C
15611564
QCString outDir = Config_getString(DOCBOOK_OUTPUT);
15621565
std::string inBuf;
15631566
readInputFile(fileName,inBuf);
1564-
QCString baseName = PlantumlManager::instance().writePlantUMLSource(outDir,
1567+
std::vector<QCString> baseNameVector = PlantumlManager::instance().writePlantUMLSource(outDir,
15651568
QCString(),inBuf.c_str(),PlantumlManager::PUML_BITMAP,QCString(),srcFile,srcLine,false);
1566-
baseName=makeBaseName(baseName);
1567-
PlantumlManager::instance().generatePlantUMLOutput(baseName,outDir,PlantumlManager::PUML_BITMAP);
1568-
m_t << "<para>\n";
1569-
visitPreStart(m_t, children, hasCaption, relPath + baseName + ".png", width, height);
1569+
bool first = true;
1570+
for(auto &baseName: baseNameVector)
1571+
{
1572+
baseName=makeBaseName(baseName);
1573+
PlantumlManager::instance().generatePlantUMLOutput(baseName,outDir,PlantumlManager::PUML_BITMAP);
1574+
if (!first) endPlantUmlFile(hasCaption);
1575+
first = false;
1576+
m_t << "<para>\n";
1577+
visitPreStart(m_t, children, hasCaption, relPath + baseName + ".png", width, height);
1578+
}
15701579
}
15711580

15721581
void DocbookDocVisitor::endPlantUmlFile(bool hasCaption)

src/htmldocvisitor.cpp

+22-16
Original file line numberDiff line numberDiff line change
@@ -675,13 +675,16 @@ void HtmlDocVisitor::operator()(const DocVerbatim &s)
675675
{
676676
format = PlantumlManager::PUML_SVG;
677677
}
678-
QCString baseName = PlantumlManager::instance().writePlantUMLSource(
678+
std::vector<QCString> baseNameVector = PlantumlManager::instance().writePlantUMLSource(
679679
htmlOutput,s.exampleFile(),
680680
s.text(),format,s.engine(),s.srcFile(),s.srcLine(),true);
681-
m_t << "<div class=\"plantumlgraph\">\n";
682-
writePlantUMLFile(baseName,s.relPath(),s.context(),s.srcFile(),s.srcLine());
683-
visitCaption(m_t, s);
684-
m_t << "</div>\n";
681+
for(const auto &baseName: baseNameVector)
682+
{
683+
m_t << "<div class=\"plantumlgraph\">\n";
684+
writePlantUMLFile(baseName,s.relPath(),s.context(),s.srcFile(),s.srcLine());
685+
visitCaption(m_t, s);
686+
m_t << "</div>\n";
687+
}
685688
forceStartParagraph(s);
686689
}
687690
break;
@@ -1836,22 +1839,25 @@ void HtmlDocVisitor::operator()(const DocPlantUmlFile &df)
18361839
}
18371840
std::string inBuf;
18381841
readInputFile(df.file(),inBuf);
1839-
QCString baseName = PlantumlManager::instance().writePlantUMLSource(
1842+
std::vector<QCString> baseNameVector = PlantumlManager::instance().writePlantUMLSource(
18401843
htmlOutput,QCString(),
18411844
inBuf.c_str(),format,QCString(),df.srcFile(),df.srcLine(),false);
1842-
baseName=makeBaseName(baseName);
1843-
m_t << "<div class=\"plantumlgraph\">\n";
1844-
writePlantUMLFile(baseName,df.relPath(),QCString(),df.srcFile(),df.srcLine());
1845-
if (df.hasCaption())
1846-
{
1847-
m_t << "<div class=\"caption\">\n";
1848-
}
1849-
visitChildren(df);
1850-
if (df.hasCaption())
1845+
for(auto &baseName: baseNameVector)
18511846
{
1847+
baseName=makeBaseName(baseName);
1848+
m_t << "<div class=\"plantumlgraph\">\n";
1849+
writePlantUMLFile(baseName,df.relPath(),QCString(),df.srcFile(),df.srcLine());
1850+
if (df.hasCaption())
1851+
{
1852+
m_t << "<div class=\"caption\">\n";
1853+
}
1854+
visitChildren(df);
1855+
if (df.hasCaption())
1856+
{
1857+
m_t << "</div>\n";
1858+
}
18521859
m_t << "</div>\n";
18531860
}
1854-
m_t << "</div>\n";
18551861
forceStartParagraph(df);
18561862
}
18571863

src/latexdocvisitor.cpp

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

556-
writePlantUMLFile(baseName, s);
556+
for(const auto &baseName: baseNameVector)
557+
{
558+
writePlantUMLFile(baseName, s);
559+
}
557560
}
558561
break;
559562
}
@@ -2067,19 +2070,25 @@ void LatexDocVisitor::startPlantUmlFile(const QCString &fileName,
20672070
readInputFile(fileName,inBuf);
20682071

20692072
bool useBitmap = inBuf.find("@startditaa") != std::string::npos;
2070-
QCString baseName = PlantumlManager::instance().writePlantUMLSource(
2073+
std::vector<QCString> baseNameVector = PlantumlManager::instance().writePlantUMLSource(
20712074
outDir,QCString(),inBuf.c_str(),
20722075
useBitmap ? PlantumlManager::PUML_BITMAP : PlantumlManager::PUML_EPS,
20732076
QCString(),srcFile,srcLine,false);
2074-
baseName=makeBaseName(baseName);
2075-
QCString shortName = makeShortName(baseName);
2076-
if (useBitmap)
2077+
bool first = true;
2078+
for(auto &baseName: baseNameVector)
20772079
{
2078-
if (shortName.find('.')==-1) shortName += ".png";
2080+
baseName=makeBaseName(baseName);
2081+
QCString shortName = makeShortName(baseName);
2082+
if (useBitmap)
2083+
{
2084+
if (shortName.find('.')==-1) shortName += ".png";
2085+
}
2086+
PlantumlManager::instance().generatePlantUMLOutput(baseName,outDir,
2087+
useBitmap ? PlantumlManager::PUML_BITMAP : PlantumlManager::PUML_EPS);
2088+
if (!first) endPlantUmlFile(hasCaption);
2089+
first = false;
2090+
visitPreStart(m_t,hasCaption, shortName, width, height);
20792091
}
2080-
PlantumlManager::instance().generatePlantUMLOutput(baseName,outDir,
2081-
useBitmap ? PlantumlManager::PUML_BITMAP : PlantumlManager::PUML_EPS);
2082-
visitPreStart(m_t,hasCaption, shortName, width, height);
20832092
}
20842093

20852094
void LatexDocVisitor::endPlantUmlFile(bool hasCaption)

src/plantuml.cpp

+138-41
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)