Doxygen
Loading...
Searching...
No Matches
cite.cpp
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 2020 by Dimitri van Heesch
4 * Based on a patch by David Munger
5 *
6 * Permission to use, copy, modify, and distribute this software and its
7 * documentation under the terms of the GNU General Public License is hereby
8 * granted. No representations are made about the suitability of this software
9 * for any purpose. It is provided "as is" without express or implied warranty.
10 * See the GNU General Public License for more details.
11 *
12 * Documents produced by Doxygen are derivative works derived from the
13 * input used in their production; they are not affected by this license.
14 *
15 */
16
17#include "cite.h"
18#include "config.h"
19#include "language.h"
20#include "message.h"
21#include "portable.h"
22#include "resourcemgr.h"
23#include "util.h"
24#include "debug.h"
25#include "fileinfo.h"
26#include "dir.h"
27#include "growbuf.h"
28#include "entry.h"
29#include "commentscan.h"
30#include "linkedmap.h"
31
32#include <map>
33#include <unordered_map>
34#include <string>
35#include <fstream>
36
37const char *bibTmpFile = "bibTmpFile_";
38const char *bibTmpDir = "bibTmpDir/";
39
40//! class that provide information about the p[osition of a citation name
42{
43 public:
44 CitePosition(const QCString &fn, int l) : fileName(fn), lineNr(l) {}
45
47 int lineNr;
48};
49
50static QCString getBibFile(const QCString &inFile)
51{
52 QCString name = inFile;
53 if (!name.isEmpty() && !name.endsWith(".bib")) name+=".bib";
54 return name;
55}
56
57class CiteInfoImpl : public CiteInfo
58{
59 public:
62
63 QCString label() const override { return m_label; }
64 QCString text() const override { return m_text; }
65 QCString shortAuthor() const override { return m_shortAuthor; }
66 QCString year() const override { return m_year; }
67
68 void setText(const QCString &s) { m_text = s; }
69 void setShortAuthor(const QCString &s) { m_shortAuthor = s; }
70 void setYear(const QCString &s) { m_year = s; }
71
72 private:
77};
78
80{
81 std::map< std::string,std::unique_ptr<CiteInfoImpl> > entries;
82 std::unordered_map< int,std::string > formulaCite;
83 std::unordered_map< std::string, CitePosition > citePosition;
84};
85
87{
88 static CitationManager ct;
89 return ct;
90}
91
95
97{
98 QCString lowerCaseLabel = label.lower();
99 p->entries.emplace(lowerCaseLabel.str(),std::make_unique<CiteInfoImpl>(lowerCaseLabel));
100}
101
102const CiteInfo *CitationManager::find(const QCString &label) const
103{
104 auto it = p->entries.find(label.lower().str());
105 if (it!=p->entries.end())
106 {
107 return it->second.get();
108 }
109 return nullptr;
110}
111
113{
114 p->entries.clear();
115}
116
118{
119 size_t numFiles = Config_getList(CITE_BIB_FILES).size();
120 return (numFiles==0 || p->entries.empty());
121}
122
124{
125 return "citelist";
126}
127
129{
130 return "CITEREF_";
131}
132
134{
135 // sanity checks
136 if (bibFile.isEmpty())
137 {
138 return;
139 }
140 FileInfo fi(bibFile.str());
141 if (!fi.exists())
142 {
143 err("bib file {} not found!\n",bibFile);
144 return;
145 }
146 std::ifstream f = Portable::openInputStream(bibFile);
147 if (!f.is_open())
148 {
149 err("could not open file {} for reading\n",bibFile);
150 return;
151 }
152
153 // search for citation cross references
154 QCString citeName;
155
156 std::string lineStr;
157 int lineCount = 0;
158 while (getline(f,lineStr))
159 {
160 int i = -1;
161 QCString line(lineStr);
162 lineCount++;
163 if (line.stripWhiteSpace().startsWith("@"))
164 {
165 // assumption entry like: "@book { name," or "@book { name" (spaces optional)
166 int j = line.find('{');
167 // when no {, go hunting for it
168 while (j==-1 && getline(f,lineStr))
169 {
170 line = lineStr;
171 lineCount++;
172 j = line.find('{');
173 }
174 // search for the name
175 citeName = "";
176 if (!f.eof() && j!=-1) // to prevent something like "@manual ," and no { found
177 {
178 int k = line.find(',',j);
179 j++;
180 // found a line "@....{.....,...." or "@.....{....."
181 // ^=j ^=k ^=j k=-1
182 while (!f.eof() && citeName.isEmpty())
183 {
184 if (k!=-1)
185 {
186 citeName = line.mid(static_cast<size_t>(j),static_cast<size_t>(k-j));
187 }
188 else
189 {
190 citeName = line.mid(static_cast<size_t>(j));
191 }
192 citeName = citeName.stripWhiteSpace();
193 j = 0;
194 if (citeName.isEmpty() && getline(f,lineStr))
195 {
196 line = lineStr;
197 lineCount++;
198 k = line.find(',');
199 }
200 }
201 }
202 //printf("citeName = #%s#\n",qPrint(citeName));
203 if (!citeName.isEmpty())
204 {
205 std::string lCiteName = citeName.lower().str();
206 auto it = p->citePosition.find(lCiteName);
207 if (it != p->citePosition.end())
208 {
209 warn(bibFile,lineCount,"multiple use of citation name '{}', (first occurrence: {}, line {})",
210 lCiteName,it->second.fileName,it->second.lineNr);
211 }
212 else
213 {
214 p->citePosition.emplace(lCiteName,CitePosition(bibFile,lineCount));
215 }
216 }
217 }
218 else if ((i=line.find("crossref"))!=-1 && !citeName.isEmpty()) /* assumption cross reference is on one line and the only item */
219 {
220 int j = line.find('{',i);
221 int k = line.find('}',i);
222 if (j>i && k>j)
223 {
224 QCString crossrefName = line.mid(static_cast<size_t>(j+1),static_cast<uint32_t>(k-j-1));
225 // check if the reference with the cross reference is used
226 // insert cross reference when cross reference has not yet been added.
227 if (find(citeName) && !find(crossrefName)) // not found yet
228 {
229 insert(crossrefName);
230 }
231 }
232 }
233 }
234}
235
236const std::string g_formulaMarker = "CITE_FORMULA_";
237
239{
240 if (s.isEmpty()) return s;
241 GrowBuf growBuf;
242 GrowBuf formulaBuf;
243 bool insideFormula = false;
244 int citeFormulaCnt = 1;
245 const size_t tmpLen = 30;
246 char tmp[tmpLen];
247 const char *ps=s.data();
248 char c = 0;
249 while ((c=*ps++))
250 {
251 if (insideFormula)
252 {
253 switch (c)
254 {
255 case '\\':
256 formulaBuf.addChar(c);
257 c = *ps++;
258 formulaBuf.addChar(c);
259 break;
260 case '\n':
261 formulaBuf.addChar(c);
262 formulaBuf.addChar(0);
263 growBuf.addChar('$');
264 growBuf.addStr(formulaBuf.get());
265 insideFormula = false;
266 formulaBuf.clear();
267 break;
268 case '$':
269 qsnprintf(tmp,tmpLen,"%s%06d",g_formulaMarker.c_str(),citeFormulaCnt);
270 formulaBuf.addChar(0);
271 p->formulaCite.emplace(citeFormulaCnt,std::string("\\f$") + formulaBuf.get() + "\\f$");
272 citeFormulaCnt++;
273 // need { and } due to the capitalization rules of bibtex.
274 growBuf.addChar('{');
275 growBuf.addStr(tmp);
276 growBuf.addChar('}');
277 insideFormula = false;
278 formulaBuf.clear();
279 break;
280 default:
281 formulaBuf.addChar(c);
282 break;
283 }
284 }
285 else
286 {
287 switch (c)
288 {
289 case '\\':
290 growBuf.addChar(c);
291 c = *ps++;
292 growBuf.addChar(c);
293 break;
294 case '$':
295 insideFormula = true;
296 break;
297 default:
298 growBuf.addChar(c);
299 break;
300 }
301 }
302 }
303 if (insideFormula)
304 {
305 formulaBuf.addChar(0);
306 growBuf.addStr(formulaBuf.get());
307 formulaBuf.clear();
308 }
309 growBuf.addChar(0);
310 return growBuf.get();
311}
312
314{
315 if (s.isEmpty()) return s;
316 QCString t;
317 int pos=0;
318 int i = -1;
319 while ((i=s.find(g_formulaMarker.c_str(),pos))!=-1)
320 {
321 t += s.mid(pos,i-pos);
322 int markerSize = static_cast<int>( g_formulaMarker.length());
323 int markerId = atoi(s.mid(i+markerSize,6).data());
324 auto it = p->formulaCite.find(markerId);
325 if (it != p->formulaCite.end()) t += it->second;
326 pos = i + markerSize+6;
327 }
328 t += s.mid(pos);
329 //printf("replaceFormulas(%s)=%s\n",qPrint(s),qPrint(t));
330 return t;
331}
332
334{
335 //printf("** CitationManager::generatePage() count=%d\n",m_ordering.count());
336
337 // do not generate an empty citations page
338 if (isEmpty()) return; // nothing to cite
339
340 bool citeDebug = Debug::isFlagSet(Debug::Cite);
341
342 // 0. add cross references from the bib files to the cite dictionary
343 const StringVector &citeDataList = Config_getList(CITE_BIB_FILES);
344 for (const auto &bibdata : citeDataList)
345 {
346 QCString bibFile = getBibFile(QCString(bibdata));
348 }
349
350 // 1. generate file with markers and citations to OUTPUT_DIRECTORY
351 QCString outputDir = Config_getString(OUTPUT_DIRECTORY);
352 QCString citeListFile = outputDir+"/citelist.doc";
353 {
354 std::ofstream t = Portable::openOutputStream(citeListFile);
355 if (!t.is_open())
356 {
357 err("could not open file {} for writing\n",citeListFile);
358 }
359 t << "<!-- BEGIN CITATIONS -->\n";
360 t << "<!--\n";
361 for (const auto &it : p->entries)
362 {
363 t << "\\citation{" << it.second->label() << "}\n";
364 }
365 t << "-->\n";
366 t << "<!-- END CITATIONS -->\n";
367 t << "<!-- BEGIN BIBLIOGRAPHY -->\n";
368 t << "<!-- END BIBLIOGRAPHY -->\n";
369 t.close();
370 }
371
372 // 2. generate bib2xhtml
373 QCString bib2xhtmlFile = outputDir+"/bib2xhtml.pl";
374 ResourceMgr::instance().copyResource("bib2xhtml.pl",outputDir);
375
376 // 3. generate doxygen.bst
377 QCString doxygenBstFile = outputDir+"/doxygen.bst";
378 ResourceMgr::instance().copyResource("doxygen.bst",outputDir);
379
380 // 4. for all formats we just copy the bib files to as special output directory
381 // so bibtex can find them without path (bibtex doesn't support paths or
382 // filenames with spaces!)
383 // Strictly not required when only latex is generated
384 QCString bibOutputDir = outputDir+"/"+bibTmpDir;
385 QCString bibOutputFiles = "";
386 Dir thisDir;
387 if (!thisDir.exists(bibOutputDir.str()) && !thisDir.mkdir(bibOutputDir.str()))
388 {
389 err("Failed to create temporary output directory '{}', skipping citations\n",bibOutputDir);
390 return;
391 }
392 int i = 0;
393 for (const auto &bibdata : citeDataList)
394 {
395 QCString bibFile = getBibFile(QCString(bibdata));
396 FileInfo fi(bibFile.str());
397 if (fi.exists())
398 {
399 if (!bibFile.isEmpty())
400 {
401 ++i;
402 std::ifstream f_org = Portable::openInputStream(bibFile);
403 if (!f_org.is_open())
404 {
405 err("could not open file {} for reading\n",bibFile);
406 }
407 std::ofstream f_out = Portable::openOutputStream(bibOutputDir + bibTmpFile + QCString().setNum(i) + ".bib");
408 if (!f_out.is_open())
409 {
410 err("could not open file {}{}{:d}{} for reading\n",bibOutputDir,bibTmpFile,i,".bib");
411 }
412 QCString docs;
413 std::string lineStr;
414 while (getline(f_org,lineStr))
415 {
416 docs += lineStr + "\n";
417 }
418 docs = getFormulas(docs);
419 f_out << docs;
420 if (f_org.is_open()) f_org.close();
421 if (f_out.is_open()) f_out.close();
422 bibOutputFiles = bibOutputFiles + " " + bibTmpDir + bibTmpFile + QCString().setNum(i) + ".bib";
423 }
424 }
425 }
426
427 std::string oldDir = Dir::currentDirPath();
428 Dir::setCurrent(outputDir.str());
429
430 // 5. run bib2xhtml perl script on the generated file which will insert the
431 // bibliography in citelist.doc
432 QCString perlArgs = "\""+bib2xhtmlFile+"\" "+bibOutputFiles+" \""+ citeListFile+"\"";
433 if (citeDebug) perlArgs+=" -d";
434 int exitCode = Portable::system("perl",perlArgs);
435 if (exitCode!=0)
436 {
437 err("Problems running bibtex. Verify that the command 'perl --version' works from the command line. Exit code: {}\n",
438 exitCode);
439 }
440
441 Dir::setCurrent(oldDir);
442
443 // 6. read back the file
444 QCString doc;
445 {
446 std::ifstream f = Portable::openInputStream(citeListFile);
447 if (!f.is_open())
448 {
449 err("could not open file {} for reading\n",citeListFile);
450 }
451
452 bool insideBib=FALSE;
453 //printf("input=[%s]\n",qPrint(input));
454 std::string lineStr;
455 while (getline(f,lineStr))
456 {
457 QCString line(lineStr);
458 //printf("pos=%d s=%d line=[%s]\n",pos,s,qPrint(line));
459
460 if (line.find("<!-- BEGIN BIBLIOGRAPHY")!=-1) insideBib=TRUE;
461 else if (line.find("<!-- END BIBLIOGRAPH")!=-1) insideBib=FALSE;
462 // determine text to use at the location of the @cite command
463 if (insideBib && ((i=line.find("name=\"CITEREF_"))!=-1 || (i=line.find("name=\"#CITEREF_"))!=-1))
464 {
465 int j=line.find("\">[");
466 int j1=line.find("<!--[");
467 int k=line.find("]<!--");
468 int k1=line.find("]-->");
469 if (j!=-1 && k!=-1)
470 {
471 size_t ui=static_cast<size_t>(i);
472 size_t uj0=static_cast<size_t>(j);
473 size_t uj=static_cast<size_t>(j1);
474 size_t uk=static_cast<size_t>(k1);
475 QCString label = line.mid(ui+14,uj0-ui-14);
476 StringVector optList = split(line.mid(uj+5,uk-uj-5).str(),",");
477 QCString number = optList[0].c_str();
478 QCString shortAuthor = optList[1].c_str();
479 QCString year;
480 if (optList.size() == 3)
481 {
482 year = optList[2].c_str();
483 }
484 line = line.left(ui+14) + label + line.right(line.length()-uj0);
485 auto it = p->entries.find(label.lower().str());
486 //printf("label='%s' number='%s' => %p\n",qPrint(label),qPrint(number),it->second.get());
487 if (it!=p->entries.end())
488 {
489 it->second->setText(number);
490 it->second->setShortAuthor(shortAuthor);
491 it->second->setYear(year.stripWhiteSpace());
492 }
493 }
494 }
495 if (insideBib) doc+=line+"\n";
496 }
497 //printf("doc=[%s]\n",qPrint(doc));
498 }
499
500 // 7. place formulas back and run the conversion of \f$ ... \f$ to the internal required format
501 {
502 doc = replaceFormulas(doc);
503 Entry current;
504 bool needsEntry = false;
505 CommentScanner commentScanner;
506 int lineNr = 0;
507 int pos = 0;
508 GuardedSectionStack guards;
509 Protection prot = Protection::Public;
510 commentScanner.parseCommentBlock(
511 nullptr,
512 &current,
513 doc, // text
514 fileName(), // file
515 lineNr, // line of block start
516 false, // isBrief
517 false, // isJavaDocStyle
518 false, // isInBody
519 prot, // protection
520 pos, // position,
521 needsEntry,
522 false,
523 &guards
524 );
525 doc = current.doc;
526 }
527
528 // 8. add it as a page
529 addRelatedPage(fileName(),theTranslator->trCiteReferences(),doc,fileName(),1,1);
530
531 // 9. for latex we just copy the bib files to the output and let
532 // latex do this work.
533 if (Config_getBool(GENERATE_LATEX))
534 {
535 // copy bib files to the latex output dir
536 QCString latexOutputDir = Config_getString(LATEX_OUTPUT)+"/";
537 i = 0;
538 for (const auto &bibdata : citeDataList)
539 {
540 QCString bibFile = getBibFile(QCString(bibdata));
541 FileInfo fi(bibFile.str());
542 if (fi.exists())
543 {
544 if (!bibFile.isEmpty())
545 {
546 // bug_700510, multiple times the same name were overwriting; creating new names
547 // also for names with spaces
548 ++i;
549 copyFile(bibFile,latexOutputDir + bibTmpFile + QCString().setNum(i) + ".bib");
550 }
551 }
552 else
553 {
554 err("bib file {} not found!\n",bibFile);
555 }
556 }
557 }
558
559 // 10. Remove temporary files
560 if (!citeDebug)
561 {
562 thisDir.remove(citeListFile.str());
563 thisDir.remove(doxygenBstFile.str());
564 thisDir.remove(bib2xhtmlFile.str());
565 // we might try to remove too many files as empty files didn't get a corresponding new file
566 // but the remove function does not emit an error for it and we don't catch the error return
567 // so no problem.
568 for (size_t j = 1; j <= citeDataList.size(); j++)
569 {
570 QCString bibFile = bibOutputDir + bibTmpFile + QCString().setNum(static_cast<int>(j)) + ".bib";
571 thisDir.remove(bibFile.str());
572 }
573 thisDir.rmdir(bibOutputDir.str());
574 }
575}
576
578{
579 QCString result;
580 const StringVector &citeDataList = Config_getList(CITE_BIB_FILES);
581 int i = 0;
582 for (const auto &bibdata : citeDataList)
583 {
584 QCString bibFile = getBibFile(QCString(bibdata));
585 FileInfo fi(bibFile.str());
586 if (fi.exists())
587 {
588 if (!bibFile.isEmpty())
589 {
590 if (i) result += ",";
591 i++;
592 result += bibTmpFile;
593 result += QCString().setNum(i);
594 }
595 }
596 }
597 return result;
598}
static QCString getBibFile(const QCString &inFile)
Definition cite.cpp:50
const std::string g_formulaMarker
Definition cite.cpp:236
const char * bibTmpFile
Definition cite.cpp:37
const char * bibTmpDir
Definition cite.cpp:38
void insertCrossReferencesForBibFile(const QCString &bibFile)
Definition cite.cpp:133
QCString anchorPrefix() const
Definition cite.cpp:128
std::unique_ptr< Private > p
Definition cite.h:123
const CiteInfo * find(const QCString &label) const
Return the citation info for a given label.
Definition cite.cpp:102
QCString latexBibFiles()
lists the bibtex cite files in a comma separated list
Definition cite.cpp:577
static CitationManager & instance()
Definition cite.cpp:86
void clear()
clears the database
Definition cite.cpp:112
QCString replaceFormulas(const QCString &s)
Definition cite.cpp:313
void insert(const QCString &label)
Insert a citation identified by label into the database.
Definition cite.cpp:96
CitationManager()
Create the database, with an expected maximum of size entries.
Definition cite.cpp:92
QCString fileName() const
Definition cite.cpp:123
bool isEmpty() const
return TRUE if there are no citations.
Definition cite.cpp:117
void generatePage()
Generate the citations page.
Definition cite.cpp:333
QCString getFormulas(const QCString &s)
Definition cite.cpp:238
void setText(const QCString &s)
Definition cite.cpp:68
QCString m_label
Definition cite.cpp:73
QCString label() const override
Definition cite.cpp:63
QCString text() const override
Definition cite.cpp:64
QCString m_shortAuthor
Definition cite.cpp:75
QCString year() const override
Definition cite.cpp:66
QCString m_text
Definition cite.cpp:74
QCString m_year
Definition cite.cpp:76
CiteInfoImpl(const QCString &label, const QCString &text=QCString())
Definition cite.cpp:60
QCString shortAuthor() const override
Definition cite.cpp:65
void setYear(const QCString &s)
Definition cite.cpp:70
void setShortAuthor(const QCString &s)
Definition cite.cpp:69
class that provide information about the p[osition of a citation name
Definition cite.cpp:42
QCString fileName
Definition cite.cpp:46
CitePosition(const QCString &fn, int l)
Definition cite.cpp:44
int lineNr
Definition cite.cpp:47
bool parseCommentBlock(OutlineParserInterface *parser, Entry *curEntry, const QCString &comment, const QCString &fileName, int &lineNr, bool isBrief, bool isJavadocStyle, bool isInbody, Protection &prot, int &position, bool &newEntryNeeded, bool markdownEnabled, GuardedSectionStack *guards)
Invokes the comment block parser with the request to parse a single comment block.
@ Cite
Definition debug.h:41
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:132
Class representing a directory in the file system.
Definition dir.h:75
static std::string currentDirPath()
Definition dir.cpp:342
bool mkdir(const std::string &path, bool acceptsAbsPath=true) const
Definition dir.cpp:295
bool remove(const std::string &path, bool acceptsAbsPath=true) const
Definition dir.cpp:314
bool rmdir(const std::string &path, bool acceptsAbsPath=true) const
Definition dir.cpp:309
static bool setCurrent(const std::string &path)
Definition dir.cpp:350
bool exists() const
Definition dir.cpp:257
Represents an unstructured piece of information, about an entity found in the sources.
Definition entry.h:116
QCString doc
documentation block (partly parsed)
Definition entry.h:200
Minimal replacement for QFileInfo.
Definition fileinfo.h:23
bool exists() const
Definition fileinfo.cpp:30
Class representing a string buffer optimized for growing.
Definition growbuf.h:28
void addChar(char c)
Definition growbuf.h:69
void addStr(const QCString &s)
Definition growbuf.h:72
void clear()
Definition growbuf.h:68
char * get()
Definition growbuf.h:114
This is an alternative implementation of QCString.
Definition qcstring.h:101
int find(char c, int index=0, bool cs=TRUE) const
Definition qcstring.cpp:43
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:153
bool startsWith(const char *s) const
Definition qcstring.h:492
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:226
QCString lower() const
Definition qcstring.h:234
bool endsWith(const char *s) const
Definition qcstring.h:509
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:150
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition qcstring.h:245
const std::string & str() const
Definition qcstring.h:537
QCString & setNum(short n)
Definition qcstring.h:444
QCString right(size_t len) const
Definition qcstring.h:219
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition qcstring.h:159
QCString left(size_t len) const
Definition qcstring.h:214
static ResourceMgr & instance()
Returns the one and only instance of this class.
bool copyResource(const QCString &name, const QCString &targetDir) const
Copies a registered resource to a given target directory.
Interface for the comment block scanner.
std::stack< GuardedSection > GuardedSectionStack
Definition commentscan.h:48
#define Config_getList(name)
Definition config.h:38
#define Config_getBool(name)
Definition config.h:33
#define Config_getString(name)
Definition config.h:32
std::vector< std::string > StringVector
Definition containers.h:33
#define lineCount(s, len)
static void addRelatedPage(Entry *root)
Definition doxygen.cpp:328
Translator * theTranslator
Definition language.cpp:71
#define warn(file, line, fmt,...)
Definition message.h:97
#define err(fmt,...)
Definition message.h:127
std::ifstream openInputStream(const QCString &name, bool binary=false, bool openAtEnd=false)
Definition portable.cpp:676
std::ofstream openOutputStream(const QCString &name, bool append=false)
Definition portable.cpp:665
int system(const QCString &command, const QCString &args, bool commandHasConsole=true)
Definition portable.cpp:106
Portable versions of functions that are platform dependent.
#define qsnprintf
Definition qcstring.h:49
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34
std::map< std::string, std::unique_ptr< CiteInfoImpl > > entries
Definition cite.cpp:81
std::unordered_map< std::string, CitePosition > citePosition
Definition cite.cpp:83
std::unordered_map< int, std::string > formulaCite
Definition cite.cpp:82
Citation-related data.
Definition cite.h:70
Protection
Definition types.h:32
StringVector split(const std::string &s, const std::string &delimiter)
split input string s by string delimiter delimiter.
Definition util.cpp:7129
bool copyFile(const QCString &src, const QCString &dest)
Copies the contents of file with name src to the newly created file with name dest.
Definition util.cpp:6370
A bunch of utility functions.