Imported Upstream version 1.8.8
[platform/upstream/doxygen.git] / src / cite.cpp
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 <qdir.h>
25
26 //--------------------------------------------------------------------------
27
28 static const char *doxygen_bst =
29 #include "doxygen.bst.h"
30 ;
31
32 static const char *bib2xhtml_pl =
33 #include "bib2xhtml.pl.h"
34 ;
35
36 //--------------------------------------------------------------------------
37
38 const QCString CiteConsts::fileName("citelist");
39 const QCString CiteConsts::anchorPrefix("CITEREF_");
40 const QCString bibTmpFile("bibTmpFile_");
41 const QCString bibTmpDir("bibTmpDir/");
42
43 //--------------------------------------------------------------------------
44
45 CiteDict::CiteDict(int size) : m_entries(size, FALSE)
46
47   m_entries.setAutoDelete(TRUE);
48 }
49
50 void CiteDict::writeLatexBibliography(FTextStream &t)
51 {
52   if (m_entries.isEmpty())
53     return;
54
55   QCString style = Config_getString("LATEX_BIB_STYLE");
56   if (style.isEmpty())
57     style="plain";
58   QCString unit;
59   if (Config_getBool("COMPACT_LATEX"))
60     unit = "section";
61   else
62     unit = "chapter";
63   t << "% Bibliography\n"
64        "\\newpage\n"
65        "\\phantomsection\n"
66        "\\addcontentsline{toc}{" << unit << "}{" << theTranslator->trCiteReferences() << "}\n"
67        "\\bibliographystyle{" << style << "}\n"
68        "\\bibliography{";
69   QStrList &citeDataList = Config_getList("CITE_BIB_FILES");
70   QCString latexOutputDir = Config_getString("LATEX_OUTPUT")+"/";
71   int i = 0;
72   const char *bibdata = citeDataList.first();
73   while (bibdata)
74   {
75     QCString bibFile = bibdata;
76     // Note: file can now have multiple dots
77     if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib";
78     QFileInfo fi(bibFile);
79     if (fi.exists())
80     {
81       if (!bibFile.isEmpty())
82       {
83         if (i) t << ",";
84         i++;
85         t << bibTmpFile << QString().setNum(i);
86       }
87     }
88     bibdata = citeDataList.next();
89   }
90   t << "}\n"
91        "\n";
92 }
93
94 void CiteDict::insert(const char *label)
95 {
96   m_entries.insert(label,new CiteInfo(label));
97 }
98
99 CiteInfo *CiteDict::find(const char *label) const
100 {
101   return label ? m_entries.find(label) : 0;
102 }
103
104 void CiteDict::clear()
105 {
106   m_entries.clear();
107 }
108
109 bool CiteDict::isEmpty() const
110 {
111   QStrList &citeBibFiles = Config_getList("CITE_BIB_FILES");
112   return (citeBibFiles.count()==0 || m_entries.isEmpty());
113 }
114
115 void CiteDict::generatePage() const
116 {
117   //printf("** CiteDict::generatePage() count=%d\n",m_ordering.count());
118
119   // do not generate an empty citations page
120   if (isEmpty()) return; // nothing to cite
121
122   // 1. generate file with markers and citations to OUTPUT_DIRECTORY
123   QFile f;
124   QCString outputDir = Config_getString("OUTPUT_DIRECTORY");
125   QCString citeListFile = outputDir+"/citelist.doc";
126   f.setName(citeListFile);
127   if (!f.open(IO_WriteOnly)) 
128   {
129     err("could not open file %s for writing\n",citeListFile.data());
130   }
131   FTextStream t(&f);
132   t << "<!-- BEGIN CITATIONS -->" << endl;
133   t << "<!--" << endl;
134   QDictIterator<CiteInfo> it(m_entries);
135   CiteInfo *ci;
136   for (it.toFirst();(ci=it.current());++it)
137   {
138     t << "\\citation{" << ci->label << "}" << endl;
139   }
140   t << "-->" << endl;
141   t << "<!-- END CITATIONS -->" << endl;
142   t << "<!-- BEGIN BIBLIOGRAPHY -->" << endl;
143   t << "<!-- END BIBLIOGRAPHY -->" << endl;
144   f.close();
145
146   // 2. generate bib2xhtml
147   QCString bib2xhtmlFile = outputDir+"/bib2xhtml.pl";
148   f.setName(bib2xhtmlFile);
149   QCString bib2xhtml = bib2xhtml_pl;
150   if (!f.open(IO_WriteOnly)) 
151   {
152     err("could not open file %s for writing\n",bib2xhtmlFile.data());
153   }
154   f.writeBlock(bib2xhtml, bib2xhtml.length());
155   f.close();
156
157   // 3. generate doxygen.bst
158   QCString doxygenBstFile = outputDir+"/doxygen.bst";
159   QCString bstData = doxygen_bst;
160   f.setName(doxygenBstFile);
161   if (!f.open(IO_WriteOnly)) 
162   {
163     err("could not open file %s for writing\n",doxygenBstFile.data());
164   }
165   f.writeBlock(bstData, bstData.length());
166   f.close();
167
168   // 4. for all formats we just copy the bib files to as special output directory
169   //    so bibtex can find them without path (bibtex doesn't support paths or
170   //    filenames with spaces!)
171   //    Strictly not required when only latex is generated
172   QStrList &citeDataList = Config_getList("CITE_BIB_FILES");
173   QCString bibOutputDir = outputDir+"/"+bibTmpDir;
174   QCString bibOutputFiles = "";
175   QDir thisDir;
176   thisDir.mkdir(bibOutputDir);
177   const char *bibdata = citeDataList.first();
178   int i = 0;
179   while (bibdata)
180   {
181     QCString bibFile = bibdata;
182     if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib";
183     QFileInfo fi(bibFile);
184     if (fi.exists())
185     {
186       if (!bibFile.isEmpty())
187       {
188         ++i;
189         copyFile(bibFile,bibOutputDir + bibTmpFile + QCString().setNum(i) + ".bib");
190         bibOutputFiles = bibOutputFiles + " " + bibTmpDir + bibTmpFile + QCString().setNum(i) + ".bib";
191       }
192     }
193     else if (!fi.exists())
194     {
195       err("bib file %s not found!\n",bibFile.data());
196     }
197     bibdata = citeDataList.next();
198   }
199
200   QString oldDir = QDir::currentDirPath();
201   QDir::setCurrent(outputDir);
202
203   // 5. run bib2xhtml perl script on the generated file which will insert the
204   //    bibliography in citelist.doc
205   portable_system("perl","\""+bib2xhtmlFile+"\" "+bibOutputFiles+" \""+
206                          citeListFile+"\"");
207
208   QDir::setCurrent(oldDir);
209
210   // 6. read back the file
211   f.setName(citeListFile);
212   if (!f.open(IO_ReadOnly)) 
213   {
214     err("could not open file %s for reading\n",citeListFile.data());
215   }
216   bool insideBib=FALSE;
217   
218   QCString doc;
219   QFileInfo fi(citeListFile);
220   QCString input(fi.size()+1);
221   f.readBlock(input.data(),fi.size());
222   f.close();
223   input.at(fi.size())='\0';
224   int p=0,s;
225   //printf("input=[%s]\n",input.data());
226   while ((s=input.find('\n',p))!=-1)
227   {
228     QCString line = input.mid(p,s-p);
229     //printf("p=%d s=%d line=[%s]\n",p,s,line.data());
230     p=s+1;
231
232     if      (line.find("<!-- BEGIN BIBLIOGRAPHY")!=-1) insideBib=TRUE;
233     else if (line.find("<!-- END BIBLIOGRAPH")!=-1)    insideBib=FALSE;
234     else if (insideBib) doc+=line+"\n";
235     int i;
236     // determine text to use at the location of the @cite command
237     if (insideBib && (i=line.find("<a name=\"CITEREF_"))!=-1)
238     {
239       int j=line.find("\">[");
240       int k=line.find("]</a>");
241       if (j!=-1 && k!=-1)
242       {
243         QCString label = line.mid(i+17,j-i-17);
244         QCString number = line.mid(j+2,k-j-1);
245         CiteInfo *ci = m_entries.find(label);
246         //printf("label='%s' number='%s' => %p\n",label.data(),number.data(),ci);
247         if (ci)
248         {
249           ci->text = number;
250         }
251       }
252     }
253   }
254   //printf("doc=[%s]\n",doc.data());
255
256   // 7. add it as a page
257   addRelatedPage(CiteConsts::fileName,
258        theTranslator->trCiteReferences(),doc,0,CiteConsts::fileName,1,0,0,0);
259
260   // 8. for latex we just copy the bib files to the output and let 
261   //    latex do this work.
262   if (Config_getBool("GENERATE_LATEX"))
263   {
264     // copy bib files to the latex output dir
265     QStrList &citeDataList = Config_getList("CITE_BIB_FILES");
266     QCString latexOutputDir = Config_getString("LATEX_OUTPUT")+"/";
267     int i = 0;
268     const char *bibdata = citeDataList.first();
269     while (bibdata)
270     {
271       QCString bibFile = bibdata;
272       // Note: file can now have multiple dots
273       if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib";
274       QFileInfo fi(bibFile);
275       if (fi.exists())
276       {
277         if (!bibFile.isEmpty())
278         {
279           // bug_700510, multile times the same name were overwriting; creating new names
280           // also for names with spaces
281           ++i;
282           copyFile(bibFile,latexOutputDir + bibTmpFile + QCString().setNum(i) + ".bib");
283         }
284       }
285       else
286       {
287         err("bib file %s not found!\n",bibFile.data());
288       }
289       bibdata = citeDataList.next();
290     }
291   }
292
293   // 9. Remove temporary files
294   thisDir.remove(citeListFile);
295   thisDir.remove(doxygenBstFile);
296   thisDir.remove(bib2xhtmlFile);
297   bibdata = citeDataList.first();
298   // we might try to remove too many files as empty files didn't get a coresponding new file
299   // but the remove function does not emit an error for it and we don't catch the error return
300   // so no problem.
301   for (unsigned int j = 1; j <= citeDataList.count(); j++)
302   {
303     thisDir.remove(bibOutputDir + bibTmpFile + QCString().setNum(j) + ".bib");
304   }
305   thisDir.rmdir(bibOutputDir);
306 }
307