Fix for UBSan build
[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.h"
34 ;
35
36 //--------------------------------------------------------------------------
37
38 const QCString CiteConsts::fileName("citelist");
39 const QCString CiteConsts::anchorPrefix("CITEREF_");
40
41 //--------------------------------------------------------------------------
42
43 CiteDict::CiteDict(int size) : m_entries(size, FALSE)
44
45   m_entries.setAutoDelete(TRUE);
46 }
47
48 static QCString getListOfBibFiles(const QCString &sep,bool stripExtension)
49 {
50   QCString result;
51   QStrList &citeDataList = Config_getList("CITE_BIB_FILES");
52   const char *bibdata = citeDataList.first();
53   while (bibdata)
54   {
55     int i;
56     QCString bibFile = bibdata;
57     if (stripExtension && bibFile.right(4)==".bib")
58     {
59       bibFile = bibFile.left(bibFile.length()-4);
60     }
61     if (stripExtension && (i=bibFile.findRev('/'))!=-1)
62     {
63       bibFile = bibFile.mid(i+1);
64     }
65     if (!bibFile.isEmpty())
66     {
67       result+=bibFile;
68       bibdata = citeDataList.next();
69       if (bibdata)
70       {
71         result+=sep;
72       }
73     }
74     else
75     {
76       bibdata = citeDataList.next();
77     }
78   }
79   return result;
80 }
81
82 void CiteDict::writeLatexBibliography(FTextStream &t)
83 {
84   if (m_entries.count()==0) return;
85   QCString style = Config_getString("LATEX_BIB_STYLE");
86   if (style.isEmpty()) style="plain";
87   t << "\\newpage \\bibliographystyle{" << style << "}" << endl;
88   t << "\\bibliography{" << getListOfBibFiles(",",TRUE) << "}" << endl;
89 }
90
91 void CiteDict::insert(const char *label)
92 {
93   m_entries.insert(label,new CiteInfo(label));
94 }
95
96 CiteInfo *CiteDict::find(const char *label) const
97 {
98   return label ? m_entries.find(label) : 0;
99 }
100
101 void CiteDict::clear()
102 {
103   m_entries.clear();
104 }
105
106 bool CiteDict::isEmpty() const
107 {
108   QStrList &citeBibFiles = Config_getList("CITE_BIB_FILES");
109   return (citeBibFiles.count()==0 || m_entries.isEmpty());
110 }
111
112 void CiteDict::generatePage() const
113 {
114   //printf("** CiteDict::generatePage() count=%d\n",m_ordering.count());
115
116   // do not generate an empty citations page
117   if (isEmpty()) return; // nothing to cite
118
119   // 1. generate file with markers and citations to OUTPUT_DIRECTORY
120   QFile f;
121   QCString outputDir = Config_getString("OUTPUT_DIRECTORY");
122   QCString citeListFile = outputDir+"/citelist.doc";
123   f.setName(citeListFile);
124   if (!f.open(IO_WriteOnly)) 
125   {
126     err("error: could not open file %s for writing\n",citeListFile.data());
127   }
128   FTextStream t(&f);
129   t << "<!-- BEGIN CITATIONS -->" << endl;
130   t << "<!--" << endl;
131   QDictIterator<CiteInfo> it(m_entries);
132   CiteInfo *ci;
133   for (it.toFirst();(ci=it.current());++it)
134   {
135     t << "\\citation{" << ci->label << "}" << endl;
136   }
137   t << "-->" << endl;
138   t << "<!-- END CITATIONS -->" << endl;
139   t << "<!-- BEGIN BIBLIOGRAPHY -->" << endl;
140   t << "<!-- END BIBLIOGRAPHY -->" << endl;
141   f.close();
142
143   // 2. generate bib2xhtml
144   QCString bib2xhtmlFile = outputDir+"/bib2xhtml.pl";
145   f.setName(bib2xhtmlFile);
146   QCString bib2xhtml = bib2xhtml_pl;
147   if (!f.open(IO_WriteOnly)) 
148   {
149     err("error: could not open file %s for writing\n",bib2xhtmlFile.data());
150   }
151   f.writeBlock(bib2xhtml, bib2xhtml.length());
152   f.close();
153
154   // 3. generate doxygen.bst
155   QCString doxygenBstFile = outputDir+"/doxygen.bst";
156   QCString bstData = doxygen_bst;
157   f.setName(doxygenBstFile);
158   if (!f.open(IO_WriteOnly)) 
159   {
160     err("error: could not open file %s for writing\n",doxygenBstFile.data());
161   }
162   f.writeBlock(bstData, bstData.length());
163   f.close();
164
165   // 4. run bib2xhtml perl script on the generated file which will insert the
166   //    bibliography in citelist.doc
167   portable_system("perl",bib2xhtmlFile+" "+getListOfBibFiles(" ",FALSE)+" "+
168                          citeListFile);
169
170   // 5. read back the file
171   f.setName(citeListFile);
172   if (!f.open(IO_ReadOnly)) 
173   {
174     err("error: could not open file %s/citelist.doc for reading\n",outputDir.data());
175   }
176   bool insideBib=FALSE;
177   
178   QCString doc;
179   QFileInfo fi(citeListFile);
180   QCString input(fi.size()+1);
181   f.readBlock(input.data(),fi.size());
182   input.at(fi.size())='\0';
183   int p=0,s;
184   //printf("input=[%s]\n",input.data());
185   while ((s=input.find('\n',p))!=-1)
186   {
187     QCString line = input.mid(p,s-p);
188     //printf("p=%d s=%d line=[%s]\n",p,s,line.data());
189     p=s+1;
190
191     if      (line.find("<!-- BEGIN BIBLIOGRAPHY")!=-1) insideBib=TRUE;
192     else if (line.find("<!-- END BIBLIOGRAPH")!=-1)    insideBib=FALSE;
193     else if (insideBib) doc+=line+"\n";
194     int i;
195     // determine text to use at the location of the @cite command
196     if (insideBib && (i=line.find("<a name=\"CITEREF_"))!=-1)
197     {
198       int j=line.find("\">[");
199       int k=line.find("]</a>");
200       if (j!=-1 && k!=-1)
201       {
202         QCString label = line.mid(i+17,j-i-17);
203         QCString number = line.mid(j+2,k-j-1);
204         CiteInfo *ci = m_entries.find(label);
205         //printf("label='%s' number='%s' => %p\n",label.data(),number.data(),ci);
206         if (ci)
207         {
208           ci->text = number;
209         }
210       }
211     }
212   }
213   //printf("doc=[%s]\n",doc.data());
214
215   // 6. add it as a page
216   addRelatedPage(CiteConsts::fileName,
217        theTranslator->trCiteReferences(),doc,0,CiteConsts::fileName,1,0,0,0);
218
219   // 7. for latex we just copy the bib files to the output and let 
220   //    latex do this work.
221   if (Config_getBool("GENERATE_LATEX"))
222   {
223     // copy bib files to the latex output dir
224     QStrList &citeDataList = Config_getList("CITE_BIB_FILES");
225     QCString latexOutputDir = Config_getString("LATEX_OUTPUT")+"/";
226     const char *bibdata = citeDataList.first();
227     while (bibdata)
228     {
229       QCString bibFile = bibdata;
230       if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib";
231       QFileInfo fi(bibFile);
232       if (fi.exists())
233       {
234         if (!bibFile.isEmpty())
235         {
236           copyFile(bibFile,latexOutputDir+fi.fileName().data());
237         }
238       }
239       else
240       {
241         err("Error: bib file %s not found!\n",bibFile.data());
242       }
243       bibdata = citeDataList.next();
244     }
245   }
246
247   // 8. Remove temporary files
248   QDir thisDir;
249   thisDir.remove(citeListFile);
250   thisDir.remove(doxygenBstFile);
251   thisDir.remove(bib2xhtmlFile);
252
253 }
254