Blame src/cite.cpp

Packit 1c1d7e
/******************************************************************************
Packit 1c1d7e
 *
Packit 1c1d7e
 * Copyright (C) 2011 by Dimitri van Heesch
Packit 1c1d7e
 * Based on a patch by David Munger
Packit 1c1d7e
 *
Packit 1c1d7e
 * Permission to use, copy, modify, and distribute this software and its
Packit 1c1d7e
 * documentation under the terms of the GNU General Public License is hereby 
Packit 1c1d7e
 * granted. No representations are made about the suitability of this software 
Packit 1c1d7e
 * for any purpose. It is provided "as is" without express or implied warranty.
Packit 1c1d7e
 * See the GNU General Public License for more details.
Packit 1c1d7e
 *
Packit 1c1d7e
 * Documents produced by Doxygen are derivative works derived from the
Packit 1c1d7e
 * input used in their production; they are not affected by this license.
Packit 1c1d7e
 *
Packit 1c1d7e
 */
Packit 1c1d7e
Packit 1c1d7e
#include "cite.h"
Packit 1c1d7e
#include "portable.h"
Packit 1c1d7e
#include "config.h"
Packit 1c1d7e
#include "message.h"
Packit 1c1d7e
#include "util.h"
Packit 1c1d7e
#include "language.h"
Packit 1c1d7e
#include "ftextstream.h"
Packit 1c1d7e
#include "resourcemgr.h"
Packit 1c1d7e
#include <qdir.h>
Packit 1c1d7e
Packit 1c1d7e
//--------------------------------------------------------------------------
Packit 1c1d7e
Packit 1c1d7e
const QCString CiteConsts::fileName("citelist");
Packit 1c1d7e
const QCString CiteConsts::anchorPrefix("CITEREF_");
Packit 1c1d7e
const QCString bibTmpFile("bibTmpFile_");
Packit 1c1d7e
const QCString bibTmpDir("bibTmpDir/");
Packit 1c1d7e
Packit 1c1d7e
//--------------------------------------------------------------------------
Packit 1c1d7e
Packit 1c1d7e
CiteDict::CiteDict(int size) : m_entries(size, FALSE)
Packit 1c1d7e
{ 
Packit 1c1d7e
  m_entries.setAutoDelete(TRUE);
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
void CiteDict::writeLatexBibliography(FTextStream &t)
Packit 1c1d7e
{
Packit 1c1d7e
  if (m_entries.isEmpty())
Packit 1c1d7e
    return;
Packit 1c1d7e
Packit 1c1d7e
  QCString style = Config_getString(LATEX_BIB_STYLE);
Packit 1c1d7e
  if (style.isEmpty())
Packit 1c1d7e
    style="plain";
Packit 1c1d7e
  QCString unit;
Packit 1c1d7e
  if (Config_getBool(COMPACT_LATEX))
Packit 1c1d7e
    unit = "section";
Packit 1c1d7e
  else
Packit 1c1d7e
    unit = "chapter";
Packit 1c1d7e
  t << "% Bibliography\n"
Packit 1c1d7e
       "\\newpage\n"
Packit 1c1d7e
       "\\phantomsection\n";
Packit 1c1d7e
  bool pdfHyperlinks = Config_getBool(PDF_HYPERLINKS);
Packit 1c1d7e
  if (!pdfHyperlinks)
Packit 1c1d7e
  {
Packit 1c1d7e
    t << "\\clearemptydoublepage\n";
Packit 1c1d7e
    t << "\\addcontentsline{toc}{" << unit << "}{" << theTranslator->trCiteReferences() << "}\n";
Packit 1c1d7e
  }
Packit 1c1d7e
  t << "\\bibliographystyle{" << style << "}\n"
Packit 1c1d7e
       "\\bibliography{";
Packit 1c1d7e
  QStrList &citeDataList = Config_getList(CITE_BIB_FILES);
Packit 1c1d7e
  int i = 0;
Packit 1c1d7e
  const char *bibdata = citeDataList.first();
Packit 1c1d7e
  while (bibdata)
Packit 1c1d7e
  {
Packit 1c1d7e
    QCString bibFile = bibdata;
Packit 1c1d7e
    // Note: file can now have multiple dots
Packit 1c1d7e
    if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib";
Packit 1c1d7e
    QFileInfo fi(bibFile);
Packit 1c1d7e
    if (fi.exists())
Packit 1c1d7e
    {
Packit 1c1d7e
      if (!bibFile.isEmpty())
Packit 1c1d7e
      {
Packit 1c1d7e
        if (i) t << ",";
Packit 1c1d7e
        i++;
Packit 1c1d7e
        t << bibTmpFile << QString().setNum(i);
Packit 1c1d7e
      }
Packit 1c1d7e
    }
Packit 1c1d7e
    bibdata = citeDataList.next();
Packit 1c1d7e
  }
Packit 1c1d7e
  t << "}\n";
Packit 1c1d7e
  if (pdfHyperlinks)
Packit 1c1d7e
  {
Packit 1c1d7e
    t << "\\addcontentsline{toc}{" << unit << "}{" << theTranslator->trCiteReferences() << "}\n";
Packit 1c1d7e
  }
Packit 1c1d7e
  t << "\n";
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
void CiteDict::insert(const char *label)
Packit 1c1d7e
{
Packit 1c1d7e
  m_entries.insert(label,new CiteInfo(label));
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
CiteInfo *CiteDict::find(const char *label) const
Packit 1c1d7e
{
Packit 1c1d7e
  return label ? m_entries.find(label) : 0;
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
void CiteDict::clear()
Packit 1c1d7e
{
Packit 1c1d7e
  m_entries.clear();
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
bool CiteDict::isEmpty() const
Packit 1c1d7e
{
Packit 1c1d7e
  QStrList &citeBibFiles = Config_getList(CITE_BIB_FILES);
Packit 1c1d7e
  return (citeBibFiles.count()==0 || m_entries.isEmpty());
Packit 1c1d7e
}
Packit 1c1d7e
Packit 1c1d7e
void CiteDict::generatePage() const
Packit 1c1d7e
{
Packit 1c1d7e
  //printf("** CiteDict::generatePage() count=%d\n",m_ordering.count());
Packit 1c1d7e
Packit 1c1d7e
  // do not generate an empty citations page
Packit 1c1d7e
  if (isEmpty()) return; // nothing to cite
Packit 1c1d7e
Packit 1c1d7e
  // 1. generate file with markers and citations to OUTPUT_DIRECTORY
Packit 1c1d7e
  QFile f;
Packit 1c1d7e
  QCString outputDir = Config_getString(OUTPUT_DIRECTORY);
Packit 1c1d7e
  QCString citeListFile = outputDir+"/citelist.doc";
Packit 1c1d7e
  f.setName(citeListFile);
Packit 1c1d7e
  if (!f.open(IO_WriteOnly)) 
Packit 1c1d7e
  {
Packit 1c1d7e
    err("could not open file %s for writing\n",citeListFile.data());
Packit 1c1d7e
  }
Packit 1c1d7e
  FTextStream t(&f);
Packit 1c1d7e
  t << "" << endl;
Packit 1c1d7e
  t << "
Packit 1c1d7e
  QDictIterator<CiteInfo> it(m_entries);
Packit 1c1d7e
  CiteInfo *ci;
Packit 1c1d7e
  for (it.toFirst();(ci=it.current());++it)
Packit 1c1d7e
  {
Packit 1c1d7e
    t << "\\citation{" << ci->label << "}" << endl;
Packit 1c1d7e
  }
Packit 1c1d7e
  t << "-->" << endl;
Packit 1c1d7e
  t << "" << endl;
Packit 1c1d7e
  t << "" << endl;
Packit 1c1d7e
  t << "" << endl;
Packit 1c1d7e
  f.close();
Packit 1c1d7e
Packit 1c1d7e
  // 2. generate bib2xhtml
Packit 1c1d7e
  QCString bib2xhtmlFile  = outputDir+"/bib2xhtml.pl";
Packit 1c1d7e
  ResourceMgr::instance().copyResource("bib2xhtml.pl",outputDir);
Packit 1c1d7e
Packit 1c1d7e
  // 3. generate doxygen.bst
Packit 1c1d7e
  QCString doxygenBstFile = outputDir+"/doxygen.bst";
Packit 1c1d7e
  ResourceMgr::instance().copyResource("doxygen.bst",outputDir);
Packit 1c1d7e
Packit 1c1d7e
  // 4. for all formats we just copy the bib files to as special output directory
Packit 1c1d7e
  //    so bibtex can find them without path (bibtex doesn't support paths or
Packit 1c1d7e
  //    filenames with spaces!)
Packit 1c1d7e
  //    Strictly not required when only latex is generated
Packit 1c1d7e
  QStrList &citeDataList = Config_getList(CITE_BIB_FILES);
Packit 1c1d7e
  QCString bibOutputDir = outputDir+"/"+bibTmpDir;
Packit 1c1d7e
  QCString bibOutputFiles = "";
Packit 1c1d7e
  QDir thisDir;
Packit 1c1d7e
  thisDir.mkdir(bibOutputDir);
Packit 1c1d7e
  const char *bibdata = citeDataList.first();
Packit 1c1d7e
  int i = 0;
Packit 1c1d7e
  while (bibdata)
Packit 1c1d7e
  {
Packit 1c1d7e
    QCString bibFile = bibdata;
Packit 1c1d7e
    if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib";
Packit 1c1d7e
    QFileInfo fi(bibFile);
Packit 1c1d7e
    if (fi.exists())
Packit 1c1d7e
    {
Packit 1c1d7e
      if (!bibFile.isEmpty())
Packit 1c1d7e
      {
Packit 1c1d7e
        ++i;
Packit 1c1d7e
        copyFile(bibFile,bibOutputDir + bibTmpFile + QCString().setNum(i) + ".bib");
Packit 1c1d7e
        bibOutputFiles = bibOutputFiles + " " + bibTmpDir + bibTmpFile + QCString().setNum(i) + ".bib";
Packit 1c1d7e
      }
Packit 1c1d7e
    }
Packit 1c1d7e
    else if (!fi.exists())
Packit 1c1d7e
    {
Packit 1c1d7e
      err("bib file %s not found!\n",bibFile.data());
Packit 1c1d7e
    }
Packit 1c1d7e
    bibdata = citeDataList.next();
Packit 1c1d7e
  }
Packit 1c1d7e
Packit 1c1d7e
  QString oldDir = QDir::currentDirPath();
Packit 1c1d7e
  QDir::setCurrent(outputDir);
Packit 1c1d7e
Packit 1c1d7e
  // 5. run bib2xhtml perl script on the generated file which will insert the
Packit 1c1d7e
  //    bibliography in citelist.doc
Packit 1c1d7e
  int exitCode;
Packit 1c1d7e
  portable_sysTimerStop();
Packit 1c1d7e
  if ((exitCode=portable_system("perl","\""+bib2xhtmlFile+"\" "+bibOutputFiles+" \""+
Packit 1c1d7e
                         citeListFile+"\"")) != 0)
Packit 1c1d7e
  {
Packit 1c1d7e
    err("Problems running bibtex. Verify that the command 'perl --version' works from the command line. Exit code: %d\n",
Packit 1c1d7e
        exitCode);
Packit 1c1d7e
  }
Packit 1c1d7e
  portable_sysTimerStop();
Packit 1c1d7e
Packit 1c1d7e
  QDir::setCurrent(oldDir);
Packit 1c1d7e
Packit 1c1d7e
  // 6. read back the file
Packit 1c1d7e
  f.setName(citeListFile);
Packit 1c1d7e
  if (!f.open(IO_ReadOnly)) 
Packit 1c1d7e
  {
Packit 1c1d7e
    err("could not open file %s for reading\n",citeListFile.data());
Packit 1c1d7e
  }
Packit 1c1d7e
  bool insideBib=FALSE;
Packit 1c1d7e
  
Packit 1c1d7e
  QCString doc;
Packit 1c1d7e
  QFileInfo fi(citeListFile);
Packit 1c1d7e
  QCString input(fi.size()+1);
Packit 1c1d7e
  f.readBlock(input.rawData(),fi.size());
Packit 1c1d7e
  f.close();
Packit 1c1d7e
  input.at(fi.size())='\0';
Packit 1c1d7e
  int p=0,s;
Packit 1c1d7e
  //printf("input=[%s]\n",input.data());
Packit 1c1d7e
  while ((s=input.find('\n',p))!=-1)
Packit 1c1d7e
  {
Packit 1c1d7e
    QCString line = input.mid(p,s-p);
Packit 1c1d7e
    //printf("p=%d s=%d line=[%s]\n",p,s,line.data());
Packit 1c1d7e
    p=s+1;
Packit 1c1d7e
Packit 1c1d7e
    if      (line.find("
Packit 1c1d7e
    else if (line.find("
Packit 1c1d7e
    else if (insideBib) doc+=line+"\n";
Packit 1c1d7e
    int i;
Packit 1c1d7e
    // determine text to use at the location of the @cite command
Packit 1c1d7e
    if (insideBib && (i=line.find("name=\"CITEREF_"))!=-1)
Packit 1c1d7e
    {
Packit 1c1d7e
      int j=line.find("\">[");
Packit 1c1d7e
      int k=line.find("]");
Packit 1c1d7e
      if (j!=-1 && k!=-1)
Packit 1c1d7e
      {
Packit 1c1d7e
        QCString label = line.mid(i+14,j-i-14);
Packit 1c1d7e
        QCString number = line.mid(j+2,k-j-1);
Packit 1c1d7e
        CiteInfo *ci = m_entries.find(label);
Packit 1c1d7e
        //printf("label='%s' number='%s' => %p\n",label.data(),number.data(),ci);
Packit 1c1d7e
        if (ci)
Packit 1c1d7e
        {
Packit 1c1d7e
          ci->text = number;
Packit 1c1d7e
        }
Packit 1c1d7e
      }
Packit 1c1d7e
    }
Packit 1c1d7e
  }
Packit 1c1d7e
  //printf("doc=[%s]\n",doc.data());
Packit 1c1d7e
Packit 1c1d7e
  // 7. add it as a page
Packit 1c1d7e
  addRelatedPage(CiteConsts::fileName,
Packit 1c1d7e
       theTranslator->trCiteReferences(),doc,0,CiteConsts::fileName,1,0,0,0);
Packit 1c1d7e
Packit 1c1d7e
  // 8. for latex we just copy the bib files to the output and let 
Packit 1c1d7e
  //    latex do this work.
Packit 1c1d7e
  if (Config_getBool(GENERATE_LATEX))
Packit 1c1d7e
  {
Packit 1c1d7e
    // copy bib files to the latex output dir
Packit 1c1d7e
    QStrList &citeDataList = Config_getList(CITE_BIB_FILES);
Packit 1c1d7e
    QCString latexOutputDir = Config_getString(LATEX_OUTPUT)+"/";
Packit 1c1d7e
    int i = 0;
Packit 1c1d7e
    const char *bibdata = citeDataList.first();
Packit 1c1d7e
    while (bibdata)
Packit 1c1d7e
    {
Packit 1c1d7e
      QCString bibFile = bibdata;
Packit 1c1d7e
      // Note: file can now have multiple dots
Packit 1c1d7e
      if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib";
Packit 1c1d7e
      QFileInfo fi(bibFile);
Packit 1c1d7e
      if (fi.exists())
Packit 1c1d7e
      {
Packit 1c1d7e
        if (!bibFile.isEmpty())
Packit 1c1d7e
        {
Packit 1c1d7e
          // bug_700510, multile times the same name were overwriting; creating new names
Packit 1c1d7e
          // also for names with spaces
Packit 1c1d7e
          ++i;
Packit 1c1d7e
          copyFile(bibFile,latexOutputDir + bibTmpFile + QCString().setNum(i) + ".bib");
Packit 1c1d7e
        }
Packit 1c1d7e
      }
Packit 1c1d7e
      else
Packit 1c1d7e
      {
Packit 1c1d7e
        err("bib file %s not found!\n",bibFile.data());
Packit 1c1d7e
      }
Packit 1c1d7e
      bibdata = citeDataList.next();
Packit 1c1d7e
    }
Packit 1c1d7e
  }
Packit 1c1d7e
Packit 1c1d7e
  // 9. Remove temporary files
Packit 1c1d7e
  thisDir.remove(citeListFile);
Packit 1c1d7e
  thisDir.remove(doxygenBstFile);
Packit 1c1d7e
  thisDir.remove(bib2xhtmlFile);
Packit 1c1d7e
  // we might try to remove too many files as empty files didn't get a corresponding new file
Packit 1c1d7e
  // but the remove function does not emit an error for it and we don't catch the error return
Packit 1c1d7e
  // so no problem.
Packit 1c1d7e
  for (unsigned int j = 1; j <= citeDataList.count(); j++)
Packit 1c1d7e
  {
Packit 1c1d7e
    thisDir.remove(bibOutputDir + bibTmpFile + QCString().setNum(j) + ".bib");
Packit 1c1d7e
  }
Packit 1c1d7e
  thisDir.rmdir(bibOutputDir);
Packit 1c1d7e
}
Packit 1c1d7e