Doxygen
cite.cpp
浏览该文件的文档.
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 
28 #include <map>
29 #include <string>
30 #include <fstream>
31 
32 const char *bibTmpFile = "bibTmpFile_";
33 const char *bibTmpDir = "bibTmpDir/";
34 
35 class CiteInfoImpl : public CiteInfo
36 {
37  public:
39  : m_label(label), m_text(text) { }
40 
41  virtual QCString label() const { return m_label; }
42  virtual QCString text() const { return m_text; }
43 
44  void setText(const QCString &s) { m_text = s; }
45 
46  private:
49 };
50 
52 {
53  std::map< std::string,std::unique_ptr<CiteInfoImpl> > entries;
54 };
55 
57 {
58  static CitationManager ct;
59  return ct;
60 }
61 
63 {
64 }
65 
67 {
68  p->entries.insert(
69  std::make_pair(
70  label.str(),
71  std::make_unique<CiteInfoImpl>(label)
72  ));
73 }
74 
75 const CiteInfo *CitationManager::find(const QCString &label) const
76 {
77  auto it = p->entries.find(label.str());
78  if (it!=p->entries.end())
79  {
80  return it->second.get();
81  }
82  return 0;
83 }
84 
86 {
87  p->entries.clear();
88 }
89 
91 {
92  size_t numFiles = Config_getList(CITE_BIB_FILES).size();
93  return (numFiles==0 || p->entries.empty());
94 }
95 
97 {
98  return "citelist";
99 }
100 
102 {
103  return "CITEREF_";
104 }
105 
107 {
108  // sanity checks
109  if (bibFile.isEmpty())
110  {
111  return;
112  }
113  FileInfo fi(bibFile.str());
114  if (!fi.exists())
115  {
116  err("bib file %s not found!\n",qPrint(bibFile));
117  return;
118  }
119  std::ifstream f(bibFile.str(), std::ifstream::in);
120  if (!f.is_open())
121  {
122  err("could not open file %s for reading\n",qPrint(bibFile));
123  return;
124  }
125 
126  // search for citation cross references
127  QCString citeName;
128 
129  std::string lineStr;
130  while (getline(f,lineStr))
131  {
132  int i;
133  QCString line(lineStr);
134  if (line.stripWhiteSpace().startsWith("@"))
135  {
136  // assumption entry like: "@book { name," or "@book { name" (spaces optional)
137  int j = line.find('{');
138  // when no {, go hunting for it
139  while (j==-1 && getline(f,lineStr))
140  {
141  line = lineStr;
142  j = line.find('{');
143  }
144  // search for the name
145  citeName = "";
146  if (!f.eof() && j!=-1) // to prevent something like "@manual ," and no { found
147  {
148  int k = line.find(',',j);
149  j++;
150  // found a line "@....{.....,...." or "@.....{....."
151  // ^=j ^=k ^=j k=-1
152  while (!f.eof() && citeName.isEmpty())
153  {
154  if (k!=-1)
155  {
156  citeName = line.mid((uint)(j),(uint)(k-j));
157  }
158  else
159  {
160  citeName = line.mid((uint)(j));
161  }
162  citeName = citeName.stripWhiteSpace();
163  j = 0;
164  if (citeName.isEmpty() && getline(f,lineStr))
165  {
166  line = lineStr;
167  k = line.find(',');
168  }
169  }
170  }
171  //printf("citeName = #%s#\n",qPrint(citeName));
172  }
173  else if ((i=line.find("crossref"))!=-1 && !citeName.isEmpty()) /* assumption cross reference is on one line and the only item */
174  {
175  int j = line.find('{',i);
176  int k = line.find('}',i);
177  if (j>i && k>j)
178  {
179  QCString crossrefName = line.mid((uint)(j+1),(uint)(k-j-1));
180  // check if the reference with the cross reference is used
181  // insert cross reference when cross reference has not yet been added.
182  if ((p->entries.find(citeName.str())!=p->entries.end()) &&
183  (p->entries.find(crossrefName.str())==p->entries.end())) // not found yet
184  {
185  insert(crossrefName);
186  }
187  }
188  }
189  }
190 }
191 
193 {
194  //printf("** CitationManager::generatePage() count=%d\n",m_ordering.count());
195 
196  // do not generate an empty citations page
197  if (isEmpty()) return; // nothing to cite
198 
199  bool citeDebug = Debug::isFlagSet(Debug::Cite);
200 
201  // 0. add cross references from the bib files to the cite dictionary
202  const StringVector &citeDataList = Config_getList(CITE_BIB_FILES);
203  for (const auto &bibdata : citeDataList)
204  {
205  QCString bibFile = bibdata.c_str();
206  if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib";
208  }
209 
210  // 1. generate file with markers and citations to OUTPUT_DIRECTORY
211  QCString outputDir = Config_getString(OUTPUT_DIRECTORY);
212  QCString citeListFile = outputDir+"/citelist.doc";
213  {
214  std::ofstream t(citeListFile.str(),std::ofstream::out | std::ofstream::binary);
215  if (!t.is_open())
216  {
217  err("could not open file %s for writing\n",qPrint(citeListFile));
218  }
219  t << "<!-- BEGIN CITATIONS -->\n";
220  t << "<!--\n";
221  for (const auto &it : p->entries)
222  {
223  t << "\\citation{" << it.second->label() << "}\n";
224  }
225  t << "-->\n";
226  t << "<!-- END CITATIONS -->\n";
227  t << "<!-- BEGIN BIBLIOGRAPHY -->\n";
228  t << "<!-- END BIBLIOGRAPHY -->\n";
229  t.close();
230  }
231 
232  // 2. generate bib2xhtml
233  QCString bib2xhtmlFile = outputDir+"/bib2xhtml.pl";
234  ResourceMgr::instance().copyResource("bib2xhtml.pl",outputDir);
235 
236  // 3. generate doxygen.bst
237  QCString doxygenBstFile = outputDir+"/doxygen.bst";
238  ResourceMgr::instance().copyResource("doxygen.bst",outputDir);
239 
240  // 4. for all formats we just copy the bib files to as special output directory
241  // so bibtex can find them without path (bibtex doesn't support paths or
242  // filenames with spaces!)
243  // Strictly not required when only latex is generated
244  QCString bibOutputDir = outputDir+"/"+bibTmpDir;
245  QCString bibOutputFiles = "";
246  Dir thisDir;
247  if (!thisDir.exists(bibOutputDir.str()) && !thisDir.mkdir(bibOutputDir.str()))
248  {
249  err("Failed to create temporary output directory '%s', skipping citations\n",qPrint(bibOutputDir));
250  return;
251  }
252  int i = 0;
253  for (const auto &bibdata : citeDataList)
254  {
255  QCString bibFile = bibdata.c_str();
256  if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib";
257  FileInfo fi(bibFile.str());
258  if (fi.exists())
259  {
260  if (!bibFile.isEmpty())
261  {
262  ++i;
263  copyFile(bibFile,bibOutputDir + bibTmpFile + QCString().setNum(i) + ".bib");
264  bibOutputFiles = bibOutputFiles + " " + bibTmpDir + bibTmpFile + QCString().setNum(i) + ".bib";
265  }
266  }
267  }
268 
269  std::string oldDir = Dir::currentDirPath();
270  Dir::setCurrent(outputDir.str());
271 
272  // 5. run bib2xhtml perl script on the generated file which will insert the
273  // bibliography in citelist.doc
274  int exitCode;
276  QCString perlArgs = "\""+bib2xhtmlFile+"\" "+bibOutputFiles+" \""+ citeListFile+"\"";
277  if (citeDebug) perlArgs+=" -d";
278  if ((exitCode=Portable::system("perl",perlArgs)) != 0)
279  {
280  err("Problems running bibtex. Verify that the command 'perl --version' works from the command line. Exit code: %d\n",
281  exitCode);
282  }
284 
285  Dir::setCurrent(oldDir);
286 
287  // 6. read back the file
288  QCString doc;
289  {
290  std::ifstream f(citeListFile.str(),std::ifstream::in);
291  if (!f.is_open())
292  {
293  err("could not open file %s for reading\n",qPrint(citeListFile));
294  }
295 
296  bool insideBib=FALSE;
297  //printf("input=[%s]\n",qPrint(input));
298  std::string lineStr;
299  while (getline(f,lineStr))
300  {
301  QCString line(lineStr);
302  //printf("pos=%d s=%d line=[%s]\n",pos,s,qPrint(line));
303 
304  if (line.find("<!-- BEGIN BIBLIOGRAPHY")!=-1) insideBib=TRUE;
305  else if (line.find("<!-- END BIBLIOGRAPH")!=-1) insideBib=FALSE;
306  // determine text to use at the location of the @cite command
307  if (insideBib && (i=line.find("name=\"CITEREF_"))!=-1)
308  {
309  int j=line.find("\">[");
310  int k=line.find("]</a>");
311  if (j!=-1 && k!=-1)
312  {
313  uint ui=(uint)i;
314  uint uj=(uint)j;
315  uint uk=(uint)k;
316  QCString label = line.mid(ui+14,uj-ui-14);
317  QCString number = line.mid(uj+2,uk-uj-1);
318  label = substitute(substitute(label,"&ndash;","--"),"&mdash;","---");
319  line = line.left(ui+14) + label + line.right(line.length()-uj);
320  auto it = p->entries.find(label.str());
321  //printf("label='%s' number='%s' => %p\n",qPrint(label),qPrint(number),it->second.get());
322  if (it!=p->entries.end())
323  {
324  it->second->setText(number);
325  }
326  }
327  }
328  if (insideBib) doc+=line+"\n";
329  }
330  //printf("doc=[%s]\n",qPrint(doc));
331  }
332 
333  // 7. add it as a page
335 
336  // 8. for latex we just copy the bib files to the output and let
337  // latex do this work.
338  if (Config_getBool(GENERATE_LATEX))
339  {
340  // copy bib files to the latex output dir
341  QCString latexOutputDir = Config_getString(LATEX_OUTPUT)+"/";
342  i = 0;
343  for (const auto &bibdata : citeDataList)
344  {
345  QCString bibFile = bibdata.c_str();
346  // Note: file can now have multiple dots
347  if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib";
348  FileInfo fi(bibFile.str());
349  if (fi.exists())
350  {
351  if (!bibFile.isEmpty())
352  {
353  // bug_700510, multiple times the same name were overwriting; creating new names
354  // also for names with spaces
355  ++i;
356  copyFile(bibFile,latexOutputDir + bibTmpFile + QCString().setNum(i) + ".bib");
357  }
358  }
359  else
360  {
361  err("bib file %s not found!\n",qPrint(bibFile));
362  }
363  }
364  }
365 
366  // 9. Remove temporary files
367  if (!citeDebug)
368  {
369  thisDir.remove(citeListFile.str());
370  thisDir.remove(doxygenBstFile.str());
371  thisDir.remove(bib2xhtmlFile.str());
372  // we might try to remove too many files as empty files didn't get a corresponding new file
373  // but the remove function does not emit an error for it and we don't catch the error return
374  // so no problem.
375  for (size_t j = 1; j <= citeDataList.size(); j++)
376  {
377  QCString bibFile = bibOutputDir + bibTmpFile + QCString().setNum(static_cast<ulong>(j)) + ".bib";
378  thisDir.remove(bibFile.str());
379  }
380  thisDir.rmdir(bibOutputDir.str());
381  }
382 }
383 
385 {
386  QCString result;
387  const StringVector &citeDataList = Config_getList(CITE_BIB_FILES);
388  int i = 0;
389  for (const auto &bibdata : citeDataList)
390  {
391  QCString bibFile = bibdata.c_str();
392  // Note: file can now have multiple dots
393  if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib";
394  FileInfo fi(bibFile.str());
395  if (fi.exists())
396  {
397  if (!bibFile.isEmpty())
398  {
399  if (i) result += ",";
400  i++;
401  result += bibTmpFile;
402  result += QCString().setNum(i);
403  }
404  }
405  }
406  return result;
407 }
StringVector
std::vector< std::string > StringVector
Definition: containers.h:32
ResourceMgr::copyResource
bool copyResource(const QCString &name, const QCString &targetDir) const
Copies a registered resource to a given target directory
Definition: resourcemgr.cpp:180
Dir::currentDirPath
static std::string currentDirPath()
Definition: dir.cpp:282
ResourceMgr::instance
static ResourceMgr & instance()
Returns the one and only instance of this class
Definition: resourcemgr.cpp:32
fileinfo.h
cite.h
CiteInfoImpl::CiteInfoImpl
CiteInfoImpl(const QCString &label, const QCString &text=QCString())
Definition: cite.cpp:38
CitationManager::find
const CiteInfo * find(const QCString &label) const
Return the citation info for a given label.
Definition: cite.cpp:75
Dir::remove
bool remove(const std::string &path, bool acceptsAbsPath=true) const
Definition: dir.cpp:256
Dir
Class representing a directory in the file system
Definition: dir.h:68
CitationManager::clear
void clear()
clears the database
Definition: cite.cpp:85
QCString::length
uint length() const
Returns the length of the string, not counting the 0-terminator.
Definition: qcstring.h:147
QCString::isEmpty
bool isEmpty() const
Returns TRUE iff the string is empty
Definition: qcstring.h:144
bibTmpFile
const char * bibTmpFile
Definition: cite.cpp:32
addRelatedPage
static void addRelatedPage(Entry *root)
Definition: doxygen.cpp:303
copyFile
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:6439
Debug::Cite
@ Cite
Definition: debug.h:42
QCString::str
std::string str() const
Definition: qcstring.h:442
err
void err(const char *fmt,...)
Definition: message.cpp:203
QCString::find
int find(char c, int index=0, bool cs=TRUE) const
Definition: qcstring.cpp:38
CitationManager::instance
static CitationManager & instance()
Definition: cite.cpp:56
CiteInfoImpl::label
virtual QCString label() const
Definition: cite.cpp:41
CitationManager::latexBibFiles
QCString latexBibFiles()
lists the bibtex cite files in a comma separated list
Definition: cite.cpp:384
CitationManager::p
std::unique_ptr< Private > p
Definition: cite.h:71
Debug::isFlagSet
static bool isFlagSet(DebugMask mask)
Definition: debug.cpp:99
CitationManager::CitationManager
CitationManager()
Create the database, with an expected maximum of size entries
Definition: cite.cpp:62
uint
unsigned uint
Definition: qcstring.h:40
QCString::stripWhiteSpace
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition: qcstring.h:243
CiteInfoImpl::text
virtual QCString text() const
Definition: cite.cpp:42
FileInfo::exists
bool exists() const
Definition: fileinfo.cpp:30
QCString::left
QCString left(size_t len) const
Definition: qcstring.h:212
message.h
CitationManager
Citation manager class.
Definition: cite.h:37
ulong
unsigned long ulong
Definition: qcstring.h:41
theTranslator
Translator * theTranslator
Definition: language.cpp:156
resourcemgr.h
CitationManager::insert
void insert(const QCString &label)
Insert a citation identified by label into the database
Definition: cite.cpp:66
CitationManager::isEmpty
bool isEmpty() const
return TRUE if there are no citations.
Definition: cite.cpp:90
language.h
CitationManager::generatePage
void generatePage()
Generate the citations page
Definition: cite.cpp:192
CiteInfoImpl
Definition: cite.cpp:35
TRUE
#define TRUE
Definition: qcstring.h:36
Portable::system
int system(const QCString &command, const QCString &args, bool commandHasConsole=true)
Definition: portable.cpp:42
Dir::setCurrent
static bool setCurrent(const std::string &path)
Definition: dir.cpp:290
CitationManager::Private
Definition: cite.cpp:51
CiteInfoImpl::m_text
QCString m_text
Definition: cite.cpp:48
CiteInfoImpl::setText
void setText(const QCString &s)
Definition: cite.cpp:44
QCString::setNum
QCString & setNum(short n)
Definition: qcstring.h:372
CiteInfo
Citation-related data.
Definition: cite.h:25
CitationManager::insertCrossReferencesForBibFile
void insertCrossReferencesForBibFile(const QCString &bibFile)
Definition: cite.cpp:106
QCString::mid
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition: qcstring.h:224
substitute
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
Definition: qcstring.cpp:465
CitationManager::Private::entries
std::map< std::string, std::unique_ptr< CiteInfoImpl > > entries
Definition: cite.cpp:53
Translator::trCiteReferences
virtual QCString trCiteReferences()=0
Config_getBool
#define Config_getBool(name)
Definition: config.h:33
CiteInfoImpl::m_label
QCString m_label
Definition: cite.cpp:47
CitationManager::fileName
QCString fileName() const
Definition: cite.cpp:96
QCString::startsWith
bool startsWith(const char *s) const
Definition: qcstring.h:408
FileInfo
Minimal replacement for QFileInfo.
Definition: fileinfo.h:22
qPrint
const char * qPrint(const char *s)
Definition: qcstring.h:589
Config_getString
#define Config_getString(name)
Definition: config.h:32
bibTmpDir
const char * bibTmpDir
Definition: cite.cpp:33
config.h
Portable::sysTimerStop
void sysTimerStop()
Definition: portable.cpp:475
Dir::exists
bool exists() const
Definition: dir.cpp:199
Dir::rmdir
bool rmdir(const std::string &path, bool acceptsAbsPath=true) const
Definition: dir.cpp:251
portable.h
Portable versions of functions that are platform dependent.
dir.h
Dir::mkdir
bool mkdir(const std::string &path, bool acceptsAbsPath=true) const
Definition: dir.cpp:237
util.h
A bunch of utility functions.
QCString::right
QCString right(size_t len) const
Definition: qcstring.h:217
debug.h
CitationManager::anchorPrefix
QCString anchorPrefix() const
Definition: cite.cpp:101
Config_getList
#define Config_getList(name)
Definition: config.h:37
FALSE
#define FALSE
Definition: qcstring.h:33
QCString
This is an alternative implementation of QCString.
Definition: qcstring.h:108