cite.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * Copyright (C) 2011 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 "portable.h"
19 #include "config.h"
20 #include "message.h"
21 #include "util.h"
22 #include "language.h"
23 #include "ftextstream.h"
24 #include "resourcemgr.h"
25 #include <qdir.h>
26 
27 //--------------------------------------------------------------------------
28 
29 const QCString CiteConsts::fileName("citelist");
30 const QCString CiteConsts::anchorPrefix("CITEREF_");
31 const QCString bibTmpFile("bibTmpFile_");
32 const QCString bibTmpDir("bibTmpDir/");
33 
34 //--------------------------------------------------------------------------
35 
36 CiteDict::CiteDict(int size) : m_entries(size, FALSE)
37 {
38  m_entries.setAutoDelete(TRUE);
39 }
40 
42 {
43  if (m_entries.isEmpty())
44  return;
45 
46  QCString style = Config_getString("LATEX_BIB_STYLE");
47  if (style.isEmpty())
48  style="plain";
49  QCString unit;
50  if (Config_getBool("COMPACT_LATEX"))
51  unit = "section";
52  else
53  unit = "chapter";
54  t << "% Bibliography\n"
55  "\\newpage\n"
56  "\\phantomsection\n";
57  bool pdfHyperlinks = Config_getBool("PDF_HYPERLINKS");
58  if (!pdfHyperlinks)
59  {
60  t << "\\clearemptydoublepage\n";
61  t << "\\addcontentsline{toc}{" << unit << "}{" << theTranslator->trCiteReferences() << "}\n";
62  }
63  t << "\\bibliographystyle{" << style << "}\n"
64  "\\bibliography{";
65  QStrList &citeDataList = Config_getList("CITE_BIB_FILES");
66  int i = 0;
67  const char *bibdata = citeDataList.first();
68  while (bibdata)
69  {
70  QCString bibFile = bibdata;
71  // Note: file can now have multiple dots
72  if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib";
73  QFileInfo fi(bibFile);
74  if (fi.exists())
75  {
76  if (!bibFile.isEmpty())
77  {
78  if (i) t << ",";
79  i++;
80  t << bibTmpFile << QString().setNum(i);
81  }
82  }
83  bibdata = citeDataList.next();
84  }
85  t << "}\n";
86  if (pdfHyperlinks)
87  {
88  t << "\\addcontentsline{toc}{" << unit << "}{" << theTranslator->trCiteReferences() << "}\n";
89  }
90  t << "\n";
91 }
92 
93 void CiteDict::insert(const char *label)
94 {
95  m_entries.insert(label,new CiteInfo(label));
96 }
97 
98 CiteInfo *CiteDict::find(const char *label) const
99 {
100  return label ? m_entries.find(label) : 0;
101 }
102 
104 {
105  m_entries.clear();
106 }
107 
108 bool CiteDict::isEmpty() const
109 {
110  QStrList &citeBibFiles = Config_getList("CITE_BIB_FILES");
111  return (citeBibFiles.count()==0 || m_entries.isEmpty());
112 }
113 
115 {
116  //printf("** CiteDict::generatePage() count=%d\n",m_ordering.count());
117 
118  // do not generate an empty citations page
119  if (isEmpty()) return; // nothing to cite
120 
121  // 1. generate file with markers and citations to OUTPUT_DIRECTORY
122  QFile f;
123  QCString outputDir = Config_getString("OUTPUT_DIRECTORY");
124  QCString citeListFile = outputDir+"/citelist.doc";
125  f.setName(citeListFile);
126  if (!f.open(IO_WriteOnly))
127  {
128  err("could not open file %s for writing\n",citeListFile.data());
129  }
130  FTextStream t(&f);
131  t << "<!-- BEGIN CITATIONS -->" << endl;
132  t << "<!--" << endl;
133  QDictIterator<CiteInfo> it(m_entries);
134  CiteInfo *ci;
135  for (it.toFirst();(ci=it.current());++it)
136  {
137  t << "\\citation{" << ci->label << "}" << endl;
138  }
139  t << "-->" << endl;
140  t << "<!-- END CITATIONS -->" << endl;
141  t << "<!-- BEGIN BIBLIOGRAPHY -->" << endl;
142  t << "<!-- END BIBLIOGRAPHY -->" << endl;
143  f.close();
144 
145  // 2. generate bib2xhtml
146  QCString bib2xhtmlFile = outputDir+"/bib2xhtml.pl";
147  ResourceMgr::instance().copyResource("bib2xhtml.pl",outputDir);
148 
149  // 3. generate doxygen.bst
150  QCString doxygenBstFile = outputDir+"/doxygen.bst";
151  ResourceMgr::instance().copyResource("doxygen.bst",outputDir);
152 
153  // 4. for all formats we just copy the bib files to as special output directory
154  // so bibtex can find them without path (bibtex doesn't support paths or
155  // filenames with spaces!)
156  // Strictly not required when only latex is generated
157  QStrList &citeDataList = Config_getList("CITE_BIB_FILES");
158  QCString bibOutputDir = outputDir+"/"+bibTmpDir;
159  QCString bibOutputFiles = "";
160  QDir thisDir;
161  thisDir.mkdir(bibOutputDir);
162  const char *bibdata = citeDataList.first();
163  int i = 0;
164  while (bibdata)
165  {
166  QCString bibFile = bibdata;
167  if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib";
168  QFileInfo fi(bibFile);
169  if (fi.exists())
170  {
171  if (!bibFile.isEmpty())
172  {
173  ++i;
174  copyFile(bibFile,bibOutputDir + bibTmpFile + QCString().setNum(i) + ".bib");
175  bibOutputFiles = bibOutputFiles + " " + bibTmpDir + bibTmpFile + QCString().setNum(i) + ".bib";
176  }
177  }
178  else if (!fi.exists())
179  {
180  err("bib file %s not found!\n",bibFile.data());
181  }
182  bibdata = citeDataList.next();
183  }
184 
185  QString oldDir = QDir::currentDirPath();
186  QDir::setCurrent(outputDir);
187 
188  // 5. run bib2xhtml perl script on the generated file which will insert the
189  // bibliography in citelist.doc
190  int exitCode;
192  if ((exitCode=portable_system("perl","\""+bib2xhtmlFile+"\" "+bibOutputFiles+" \""+
193  citeListFile+"\"")) != 0)
194  {
195  err("Problems running bibtex. Verify that the command 'perl --version' works from the command line. Exit code: %d\n",
196  exitCode);
197  }
199 
200  QDir::setCurrent(oldDir);
201 
202  // 6. read back the file
203  f.setName(citeListFile);
204  if (!f.open(IO_ReadOnly))
205  {
206  err("could not open file %s for reading\n",citeListFile.data());
207  }
208  bool insideBib=FALSE;
209 
210  QCString doc;
211  QFileInfo fi(citeListFile);
212  QCString input(fi.size()+1);
213  f.readBlock(input.rawData(),fi.size());
214  f.close();
215  input.at(fi.size())='\0';
216  int p=0,s;
217  //printf("input=[%s]\n",input.data());
218  while ((s=input.find('\n',p))!=-1)
219  {
220  QCString line = input.mid(p,s-p);
221  //printf("p=%d s=%d line=[%s]\n",p,s,line.data());
222  p=s+1;
223 
224  if (line.find("<!-- BEGIN BIBLIOGRAPHY")!=-1) insideBib=TRUE;
225  else if (line.find("<!-- END BIBLIOGRAPH")!=-1) insideBib=FALSE;
226  else if (insideBib) doc+=line+"\n";
227  int i;
228  // determine text to use at the location of the @cite command
229  if (insideBib && (i=line.find("name=\"CITEREF_"))!=-1)
230  {
231  int j=line.find("\">[");
232  int k=line.find("]</a>");
233  if (j!=-1 && k!=-1)
234  {
235  QCString label = line.mid(i+14,j-i-14);
236  QCString number = line.mid(j+2,k-j-1);
237  CiteInfo *ci = m_entries.find(label);
238  //printf("label='%s' number='%s' => %p\n",label.data(),number.data(),ci);
239  if (ci)
240  {
241  ci->text = number;
242  }
243  }
244  }
245  }
246  //printf("doc=[%s]\n",doc.data());
247 
248  // 7. add it as a page
251 
252  // 8. for latex we just copy the bib files to the output and let
253  // latex do this work.
254  if (Config_getBool("GENERATE_LATEX"))
255  {
256  // copy bib files to the latex output dir
257  QStrList &citeDataList = Config_getList("CITE_BIB_FILES");
258  QCString latexOutputDir = Config_getString("LATEX_OUTPUT")+"/";
259  int i = 0;
260  const char *bibdata = citeDataList.first();
261  while (bibdata)
262  {
263  QCString bibFile = bibdata;
264  // Note: file can now have multiple dots
265  if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib";
266  QFileInfo fi(bibFile);
267  if (fi.exists())
268  {
269  if (!bibFile.isEmpty())
270  {
271  // bug_700510, multile times the same name were overwriting; creating new names
272  // also for names with spaces
273  ++i;
274  copyFile(bibFile,latexOutputDir + bibTmpFile + QCString().setNum(i) + ".bib");
275  }
276  }
277  else
278  {
279  err("bib file %s not found!\n",bibFile.data());
280  }
281  bibdata = citeDataList.next();
282  }
283  }
284 
285  // 9. Remove temporary files
286  thisDir.remove(citeListFile);
287  thisDir.remove(doxygenBstFile);
288  thisDir.remove(bib2xhtmlFile);
289  // we might try to remove too many files as empty files didn't get a coresponding new file
290  // but the remove function does not emit an error for it and we don't catch the error return
291  // so no problem.
292  for (unsigned int j = 1; j <= citeDataList.count(); j++)
293  {
294  thisDir.remove(bibOutputDir + bibTmpFile + QCString().setNum(j) + ".bib");
295  }
296  thisDir.rmdir(bibOutputDir);
297 }
298 
Traverses directory structures and contents in a platform-independent way.
Definition: qdir.h:52
void portable_sysTimerStop()
Definition: portable.cpp:415
bool isEmpty() const
Definition: qcstring.h:189
virtual bool remove(const QString &fileName, bool acceptAbsPath=TRUE)
Definition: qdir.cpp:915
#define IO_WriteOnly
Definition: qiodevice.h:62
type * first()
Definition: qinternallist.h:87
QCString label
Definition: cite.h:44
const bool FALSE
Definition: qglobal.h:370
bool copyResource(const char *name, const char *targetDir) const
static ResourceMgr & instance()
Definition: resourcemgr.cpp:35
bool copyFile(const QCString &src, const QCString &dest)
Definition: util.cpp:7966
QDict< CiteInfo > m_entries
Definition: cite.h:93
int readBlock(char *data, uint len)
Definition: qfile_unix.cpp:473
#define Config_getList(val)
Definition: config.cpp:662
The QString class provides an abstraction of Unicode text and the classic C null-terminated char arra...
Definition: qstring.h:350
Simplified and optimized version of QTextStream.
Definition: ftextstream.h:11
int find(char c, int index=0, bool cs=TRUE) const
Definition: qcstring.cpp:41
void setName(const QString &name)
Definition: qfile.cpp:167
bool isEmpty() const
Definition: cite.cpp:108
const QCString bibTmpDir("bibTmpDir/")
#define IO_ReadOnly
Definition: qiodevice.h:61
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
virtual bool mkdir(const QString &dirName, bool acceptAbsPath=TRUE) const
Definition: qdir_unix.cpp:98
QString & setNum(short, int base=10)
Definition: qstring.h:706
Citation-related data.
Definition: cite.h:34
static int input(void)
Definition: code.cpp:15695
QCString right(uint len) const
Definition: qcstring.cpp:231
bool open(int)
Definition: qfile_unix.cpp:134
static QString currentDirPath()
Definition: qdir_unix.cpp:141
virtual QCString trCiteReferences()=0
p
Definition: test.py:223
A bunch of utility functions.
const char * data() const
Definition: qcstring.h:207
#define Config_getString(val)
Definition: config.cpp:660
#define Config_getBool(val)
Definition: config.cpp:664
void generatePage() const
Definition: cite.cpp:114
CiteDict(int size)
Definition: cite.cpp:36
type * next()
Definition: qinternallist.h:89
void err(const char *fmt,...)
Definition: message.cpp:226
const QCString bibTmpFile("bibTmpFile_")
static void addRelatedPage(EntryNav *rootNav)
Definition: doxygen.cpp:577
QCString mid(uint index, uint len=0xffffffff) const
Definition: qcstring.cpp:246
The QFile class is an I/O device that operates on files.
Definition: qfile.h:50
static const QCString anchorPrefix
Definition: cite.h:30
void writeLatexBibliography(FTextStream &t)
Definition: cite.cpp:41
QCString & setNum(short n)
Definition: qcstring.cpp:469
uint size() const
CiteInfo * find(const char *label) const
Definition: cite.cpp:98
virtual bool rmdir(const QString &dirName, bool acceptAbsPath=TRUE) const
Definition: qdir_unix.cpp:104
void insert(const char *label)
Definition: cite.cpp:93
void line(double t, double *p, double &x, double &y, double &z)
QCString doc
static const QCString fileName
Definition: cite.h:29
Translator * theTranslator
Definition: language.cpp:157
QCString text
Definition: cite.h:45
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:51
uint count() const
Definition: qinternallist.h:56
void close()
Definition: qfile_unix.cpp:614
void clear()
Definition: cite.cpp:103
static QCString * s
Definition: config.cpp:1042
const bool TRUE
Definition: qglobal.h:371
Portable versions of functions that are platform dependent.
static bool setCurrent(const QString &path)
Definition: qdir_unix.cpp:134
QTextStream & endl(QTextStream &s)
bool exists() const
Definition: qfileinfo.cpp:265
int portable_system(const char *command, const char *args, bool commandHasConsole)
Definition: portable.cpp:33