diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/dot.cpp | 254 | ||||
-rw-r--r-- | src/dot.h | 13 |
2 files changed, 175 insertions, 92 deletions
diff --git a/src/dot.cpp b/src/dot.cpp index 2d4c41a..b5fa749 100644 --- a/src/dot.cpp +++ b/src/dot.cpp @@ -743,13 +743,31 @@ static void removeDotGraph(const QCString &dotName) } +/*! Calculates the md5 signature for a given graph. + * Node numbers are removed to not have md5 mismatches in case just the node + * numbers are different. + */ +static void calculateMd5Signature(QGString const & theGraph, QCString & sigStr) +{ + ASSERT(sigStr.length() >= 32); + + uchar md5_sig[16]; + + // convert to a string with regexp + QCString theGraphTemp(theGraph.data()); + // remove node numbers + theGraphTemp.replace(QRegExp("Node[0-9]*"), "Node"); + // calculate md5 + MD5Buffer((const unsigned char*)theGraphTemp.data(), theGraphTemp.length(), md5_sig); + // convert result to a string + MD5SigToString(md5_sig, sigStr.rawData(), 33); +} /*! Checks if a file "baseName".md5 exists. If so the contents - * are compared with \a md5. If equal FALSE is returned. If the .md5 - * file does not exist or its contents are not equal to \a md5, - * a new .md5 is generated with the \a md5 string as contents. + * are compared with \a md5. If equal FALSE is returned. + * The .md5 is created or updated after successful creation of the output file. */ -static bool checkAndUpdateMd5Signature(const QCString &baseName, +static bool checkMd5Signature(const QCString &baseName, const QCString &md5) { QFile f(baseName+".md5"); @@ -767,12 +785,6 @@ static bool checkAndUpdateMd5Signature(const QCString &baseName, } } f.close(); - // create checksum file - if (f.open(IO_WriteOnly)) - { - f.writeBlock(md5.data(),32); - f.close(); - } return TRUE; } @@ -811,12 +823,12 @@ int DotNodeList::compareValues(const DotNode *n1,const DotNode *n2) const //-------------------------------------------------------------------- -DotRunner::DotRunner(const QCString &file,const QCString &path, - bool checkResult,const QCString &imageName) +DotRunner::DotRunner(const QCString& baseName, const QCString& path, const QCString& md5Hash, + bool checkResult, const QCString& imageName) : m_dotExe(Config_getString(DOT_PATH)+"dot"), - m_file(file), m_path(path), + m_baseName(baseName), m_path(path), m_checkResult(checkResult), m_imageName(imageName), - m_imgExt(getDotImageExtension()) + m_imgExt(getDotImageExtension()), m_md5Hash(md5Hash) { static bool dotCleanUp = Config_getBool(DOT_CLEANUP); static bool dotMultiTargets = Config_getBool(DOT_MULTI_TARGETS); @@ -847,14 +859,14 @@ bool DotRunner::run() DotConstString *s; if (m_multiTargets) { - dotArgs=QCString("\"")+m_file.data()+"\""; + dotArgs=QCString("\"")+m_baseName.data()+".dot\""; for (li.toFirst();(s=li.current());++li) { dotArgs+=' '; dotArgs+=s->data(); } if ((exitCode=portable_system(m_dotExe.data(),dotArgs,FALSE))!=0) goto error; - dotArgs=QCString("\"")+m_file.data()+"\""; + dotArgs=QCString("\"")+m_baseName.data()+".dot\""; bool redo = FALSE; for (li.toFirst();(s=li.current());++li) { @@ -879,7 +891,7 @@ bool DotRunner::run() { for (li.toFirst();(s=li.current());++li) { - dotArgs=QCString("\"")+m_file.data()+"\" "+s->data(); + dotArgs=QCString("\"")+m_baseName.data()+".dot\" "+s->data(); if ((exitCode=portable_system(m_dotExe.data(),dotArgs,FALSE))!=0) goto error; if (s->pdfData()) { @@ -905,9 +917,18 @@ bool DotRunner::run() { //printf("removing dot file %s\n",m_file.data()); //QDir(path).remove(file); - m_cleanupItem.file.set(m_file.data()); + m_cleanupItem.file.set((QCString(m_baseName.data()) + ".dot").data()); m_cleanupItem.path.set(m_path.data()); } + if (!m_md5Hash.isEmpty()) { + // create checksum file + QFile f(QCString(m_baseName.data())+".md5"); + if (f.open(IO_WriteOnly)) + { + f.writeBlock(m_md5Hash.data(),32); + f.close(); + } + } return TRUE; error: err("Problems running dot: exit code=%d, command='%s', arguments='%s'\n", @@ -1490,6 +1511,24 @@ bool DotManager::run() return TRUE; } +bool DotManager::containsRun(const QCString& baseName, const QCString& path, const QCString& md5Hash) +{ + QListIterator<DotRunner> li(m_dotRuns); + DotRunner *dr; + for (li.toFirst();(dr=li.current());++li) + { + if (baseName != QCString(dr->getBaseName().data())) continue; + if (path != QCString(dr->getPath().data())) continue; + // we have a match + if (md5Hash != QCString(dr->getMd5Hash().data())) + { + err("md5 hash does not match for two different runs of %s !\n", (baseName + ".dot").data()); + } + return TRUE; + } + return FALSE; +} + //-------------------------------------------------------------------- @@ -2381,12 +2420,16 @@ void DotGfxHierarchyTable::createGraph(DotNode *n,FTextStream &out, } } writeGraphFooter(md5stream); - uchar md5_sig[16]; QCString sigStr(33); - MD5Buffer((const unsigned char *)theGraph.data(),theGraph.length(),md5_sig); - MD5SigToString(md5_sig,sigStr.rawData(),33); + calculateMd5Signature(theGraph, sigStr); + bool regenerate=FALSE; - if (checkAndUpdateMd5Signature(absBaseName,sigStr) || + if (DotManager::instance()->containsRun(absBaseName, d.absPath().data(), sigStr)) + { + // file is already queued + regenerate=TRUE; + } + else if (checkMd5Signature(absBaseName,sigStr) || !checkDeliverables(absImgName,absMapName)) { regenerate=TRUE; @@ -2398,7 +2441,7 @@ void DotGfxHierarchyTable::createGraph(DotNode *n,FTextStream &out, t << theGraph; f.close(); - DotRunner *dotRun = new DotRunner(dotName,d.absPath().data(),TRUE,absImgName); + DotRunner *dotRun = new DotRunner(absBaseName,d.absPath().data(),sigStr,TRUE,absImgName); dotRun->addJob(imgFmt,absImgName); dotRun->addJob(MAP_CMD,absMapName); DotManager::instance()->addRun(dotRun); @@ -3157,28 +3200,28 @@ QCString computeMd5Signature(DotNode *root, } } writeGraphFooter(md5stream); - uchar md5_sig[16]; QCString sigStr(33); - MD5Buffer((const unsigned char *)buf.data(),buf.length(),md5_sig); - MD5SigToString(md5_sig,sigStr.rawData(),33); + calculateMd5Signature(buf, sigStr); + graphStr=buf.data(); //printf("md5: %s | file: %s\n",sigStr,baseName.data()); return sigStr; } -static bool updateDotGraph(DotNode *root, +static void updateDotGraph(DotNode *root, DotNode::GraphType gt, const QCString &baseName, GraphOutputFormat format, const QCString &rank, bool renderParents, bool backArrows, + QCString & md5, const QCString &title=QCString() ) { QCString theGraph; // TODO: write graph to theGraph, then compute md5 checksum - QCString md5 = computeMd5Signature( + md5 = computeMd5Signature( root,gt,format,rank,renderParents, backArrows,title,theGraph); QFile f(baseName+".dot"); @@ -3187,7 +3230,6 @@ static bool updateDotGraph(DotNode *root, FTextStream t(&f); t << theGraph; } - return checkAndUpdateMd5Signature(baseName,md5); // graph needs to be regenerated } QCString DotClassGraph::writeGraph(FTextStream &out, @@ -3236,25 +3278,34 @@ QCString DotClassGraph::writeGraph(FTextStream &out, QCString absImgName = absBaseName+"."+imgExt; bool regenerate = FALSE; - if (updateDotGraph(m_startNode, + QCString sigStr; + updateDotGraph(m_startNode, m_graphType, absBaseName, graphFormat, m_lrRank ? "LR" : "", - m_graphType==DotNode::Inheritance, + m_graphType == DotNode::Inheritance, TRUE, + sigStr, m_startNode->label() - ) || - !checkDeliverables(graphFormat==GOF_BITMAP ? absImgName : - usePDFLatex ? absPdfName : absEpsName, - graphFormat==GOF_BITMAP && generateImageMap ? absMapName : QCString()) - ) + ); + + if (DotManager::instance()->containsRun(absBaseName, d.absPath().data(), sigStr)) + { + // file is already queued + regenerate=TRUE; + } + else if (checkMd5Signature(absBaseName,sigStr) || + !checkDeliverables(graphFormat==GOF_BITMAP ? absImgName : + usePDFLatex ? absPdfName : absEpsName, + graphFormat==GOF_BITMAP && generateImageMap ? absMapName : QCString()) + ) { regenerate=TRUE; if (graphFormat==GOF_BITMAP) // run dot to create a bitmap image { - DotRunner *dotRun = new DotRunner(absDotName, - d.absPath().data(),TRUE,absImgName); + DotRunner *dotRun = new DotRunner(absBaseName, + d.absPath().data(), sigStr, TRUE,absImgName); dotRun->addJob(imgFmt,absImgName); if (generateImageMap) dotRun->addJob(MAP_CMD,absMapName); DotManager::instance()->addRun(dotRun); @@ -3262,7 +3313,7 @@ QCString DotClassGraph::writeGraph(FTextStream &out, } else if (graphFormat==GOF_EPS) // run dot to create a .eps image { - DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE); + DotRunner *dotRun = new DotRunner(absBaseName, d.absPath().data(), sigStr, FALSE); if (usePDFLatex) { dotRun->addJob("pdf",absPdfName,absBaseName); @@ -3582,32 +3633,41 @@ QCString DotInclDepGraph::writeGraph(FTextStream &out, QCString absImgName = absBaseName+"."+imgExt; bool regenerate = FALSE; - if (updateDotGraph(m_startNode, - DotNode::Dependency, - absBaseName, - graphFormat, - "", // lrRank - FALSE, // renderParents - m_inverse, // backArrows - m_startNode->label() - ) || - !checkDeliverables(graphFormat==GOF_BITMAP ? absImgName : - usePDFLatex ? absPdfName : absEpsName, - graphFormat==GOF_BITMAP && generateImageMap ? absMapName : QCString()) - ) + QCString sigStr; + updateDotGraph(m_startNode, + DotNode::Dependency, + absBaseName, + graphFormat, + "", // lrRank + FALSE, // renderParents + m_inverse, // backArrows + sigStr, + m_startNode->label() + ); + + if (DotManager::instance()->containsRun(absBaseName, d.absPath().data(), sigStr)) + { + // file is already queued + regenerate=TRUE; + } + else if (checkMd5Signature(absBaseName,sigStr) || + !checkDeliverables(graphFormat==GOF_BITMAP ? absImgName : + usePDFLatex ? absPdfName : absEpsName, + graphFormat==GOF_BITMAP && generateImageMap ? absMapName : QCString()) + ) { regenerate=TRUE; if (graphFormat==GOF_BITMAP) { // run dot to create a bitmap image - DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),TRUE,absImgName); + DotRunner *dotRun = new DotRunner(absBaseName, d.absPath().data(), sigStr, TRUE, absImgName); dotRun->addJob(imgFmt,absImgName); if (generateImageMap) dotRun->addJob(MAP_CMD,absMapName); DotManager::instance()->addRun(dotRun); } else if (graphFormat==GOF_EPS) { - DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE); + DotRunner *dotRun = new DotRunner(absBaseName, d.absPath().data(), sigStr, FALSE); if (usePDFLatex) { dotRun->addJob("pdf",absPdfName,absBaseName); @@ -3897,26 +3957,34 @@ QCString DotCallGraph::writeGraph(FTextStream &out, GraphOutputFormat graphForma QCString absImgName = absBaseName+"."+imgExt; bool regenerate = FALSE; - - if (updateDotGraph(m_startNode, - DotNode::CallGraph, - absBaseName, - graphFormat, - m_inverse ? "RL" : "LR", // lrRank - FALSE, // renderParents - m_inverse, // backArrows - m_startNode->label() - ) || - !checkDeliverables(graphFormat==GOF_BITMAP ? absImgName : - usePDFLatex ? absPdfName : absEpsName, - graphFormat==GOF_BITMAP && generateImageMap ? absMapName : QCString()) - ) + QCString sigStr; + updateDotGraph(m_startNode, + DotNode::CallGraph, + absBaseName, + graphFormat, + m_inverse ? "RL" : "LR", // lrRank + FALSE, // renderParents + m_inverse, // backArrows + sigStr, + m_startNode->label() + ); + + if (DotManager::instance()->containsRun(absBaseName, d.absPath().data(), sigStr)) + { + // file is already queued + regenerate=TRUE; + } + else if (checkMd5Signature(absBaseName,sigStr) || + !checkDeliverables(graphFormat==GOF_BITMAP ? absImgName : + usePDFLatex ? absPdfName : absEpsName, + graphFormat==GOF_BITMAP && generateImageMap ? absMapName : QCString()) + ) { regenerate=TRUE; if (graphFormat==GOF_BITMAP) { // run dot to create a bitmap image - DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),TRUE,absImgName); + DotRunner *dotRun = new DotRunner(absBaseName, d.absPath().data(), sigStr, TRUE, absImgName); dotRun->addJob(imgFmt,absImgName); if (generateImageMap) dotRun->addJob(MAP_CMD,absMapName); DotManager::instance()->addRun(dotRun); @@ -3925,7 +3993,7 @@ QCString DotCallGraph::writeGraph(FTextStream &out, GraphOutputFormat graphForma else if (graphFormat==GOF_EPS) { // run dot to create a .eps image - DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE); + DotRunner *dotRun = new DotRunner(absBaseName, d.absPath().data(), sigStr, FALSE); if (usePDFLatex) { dotRun->addJob("pdf",absPdfName,absBaseName); @@ -4057,12 +4125,15 @@ QCString DotDirDeps::writeGraph(FTextStream &out, FTextStream md5stream(&theGraph); //m_dir->writeDepGraph(md5stream); writeDotDirDepGraph(md5stream,m_dir,linkRelations); - uchar md5_sig[16]; QCString sigStr(33); - MD5Buffer((const unsigned char *)theGraph.data(),theGraph.length(),md5_sig); - MD5SigToString(md5_sig,sigStr.rawData(),33); + calculateMd5Signature(theGraph, sigStr); bool regenerate=FALSE; - if (checkAndUpdateMd5Signature(absBaseName,sigStr) || + if (DotManager::instance()->containsRun(absBaseName, d.absPath().data(), sigStr)) + { + // file is already queued + regenerate=TRUE; + } + else if (checkMd5Signature(absBaseName,sigStr) || !checkDeliverables(graphFormat==GOF_BITMAP ? absImgName : usePDFLatex ? absPdfName : absEpsName, graphFormat==GOF_BITMAP && generateImageMap ? absMapName : QCString()) @@ -4082,14 +4153,14 @@ QCString DotDirDeps::writeGraph(FTextStream &out, if (graphFormat==GOF_BITMAP) { // run dot to create a bitmap image - DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),TRUE,absImgName); + DotRunner *dotRun = new DotRunner(absBaseName, d.absPath().data(), sigStr, TRUE, absImgName); dotRun->addJob(imgFmt,absImgName); if (generateImageMap) dotRun->addJob(MAP_CMD,absMapName); DotManager::instance()->addRun(dotRun); } else if (graphFormat==GOF_EPS) { - DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE); + DotRunner *dotRun = new DotRunner(absBaseName, d.absPath().data(), sigStr, FALSE); if (usePDFLatex) { dotRun->addJob("pdf",absPdfName,absBaseName); @@ -4200,17 +4271,19 @@ void generateGraphLegend(const char *path) md5stream << " Node18 -> Node9 [dir=\"back\",color=\"darkorchid3\",fontsize=\"" << FONTSIZE << "\",style=\"dashed\",label=\"m_usedClass\",fontname=\"" << FONTNAME << "\"];\n"; md5stream << " Node18 [shape=\"box\",label=\"Used\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classUsed" << Doxygen::htmlFileExtension << "\"];\n"; writeGraphFooter(md5stream); - uchar md5_sig[16]; QCString sigStr(33); - MD5Buffer((const unsigned char *)theGraph.data(),theGraph.length(),md5_sig); - MD5SigToString(md5_sig,sigStr.rawData(),33); + calculateMd5Signature(theGraph, sigStr); QCString absBaseName = (QCString)path+"/graph_legend"; QCString absDotName = absBaseName+".dot"; QCString imgExt = getDotImageExtension(); QCString imgFmt = Config_getEnum(DOT_IMAGE_FORMAT); QCString imgName = "graph_legend."+imgExt; QCString absImgName = absBaseName+"."+imgExt; - if (checkAndUpdateMd5Signature(absBaseName,sigStr) || + if (DotManager::instance()->containsRun(absBaseName, d.absPath().data(), sigStr)) + { + // file is already queued + } + else if (checkMd5Signature(absBaseName,sigStr) || !checkDeliverables(absImgName)) { QFile dotFile(absDotName); @@ -4226,7 +4299,7 @@ void generateGraphLegend(const char *path) // run dot to generate the a bitmap image from the graph - DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),TRUE,absImgName); + DotRunner *dotRun = new DotRunner(absBaseName, d.absPath().data(),sigStr,TRUE,absImgName); dotRun->addJob(imgFmt,absImgName); DotManager::instance()->addRun(dotRun); } @@ -4261,7 +4334,7 @@ void writeDotGraphFromFile(const char *inFile,const char *outDir, QCString absImgName = d.absPath().utf8()+"/"+imgName; QCString absOutFile = d.absPath().utf8()+"/"+outFile; - DotRunner dotRun(inFile,d.absPath().data(),FALSE,absImgName); + DotRunner dotRun(inFile,d.absPath().data(),QCString(),FALSE,absImgName); if (format==GOF_BITMAP) dotRun.addJob(imgFmt,absImgName); else // format==GOF_EPS @@ -4316,7 +4389,7 @@ void writeDotImageMapFromFile(FTextStream &t, QCString imgName = baseName+"."+imgExt; QCString absOutFile = d.absPath().utf8()+"/"+mapName; - DotRunner dotRun(inFile,d.absPath().data(),FALSE); + DotRunner dotRun(baseName,d.absPath().data(),QCString(),FALSE); dotRun.addJob(MAP_CMD,absOutFile); dotRun.preventCleanUp(); if (!dotRun.run()) @@ -4614,10 +4687,8 @@ QCString DotGroupCollaboration::writeGraph( FTextStream &t, } writeGraphFooter(md5stream); - uchar md5_sig[16]; QCString sigStr(33); - MD5Buffer((const unsigned char *)theGraph.data(),theGraph.length(),md5_sig); - MD5SigToString(md5_sig,sigStr.rawData(),33); + calculateMd5Signature(theGraph, sigStr); QCString imgExt = getDotImageExtension(); QCString imgFmt = Config_getEnum(DOT_IMAGE_FORMAT); QCString baseName = m_diskName; @@ -4630,7 +4701,12 @@ QCString DotGroupCollaboration::writeGraph( FTextStream &t, QCString absPdfName = absBaseName+".pdf"; QCString absEpsName = absBaseName+".eps"; bool regenerate=FALSE; - if (checkAndUpdateMd5Signature(absBaseName,sigStr) || + if (DotManager::instance()->containsRun(absBaseName, d.absPath().data(), sigStr)) + { + // file is already queued + regenerate=TRUE; + } + else if (checkMd5Signature(absBaseName,sigStr) || !checkDeliverables(graphFormat==GOF_BITMAP ? absImgName : usePDFLatex ? absPdfName : absEpsName, graphFormat==GOF_BITMAP /*&& generateImageMap*/ ? absMapName : QCString()) @@ -4648,7 +4724,7 @@ QCString DotGroupCollaboration::writeGraph( FTextStream &t, if (graphFormat==GOF_BITMAP) // run dot to create a bitmap image { - DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE); + DotRunner *dotRun = new DotRunner(absBaseName,d.absPath().data(),sigStr,FALSE); dotRun->addJob(imgFmt,absImgName); if (writeImageMap) dotRun->addJob(MAP_CMD,absMapName); DotManager::instance()->addRun(dotRun); @@ -4656,7 +4732,7 @@ QCString DotGroupCollaboration::writeGraph( FTextStream &t, } else if (graphFormat==GOF_EPS) { - DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE); + DotRunner *dotRun = new DotRunner(absBaseName,d.absPath().data(),sigStr,FALSE); if (usePDFLatex) { dotRun->addJob("pdf",absPdfName,absBaseName); @@ -393,8 +393,8 @@ class DotRunner }; /** Creates a runner for a dot \a file. */ - DotRunner(const QCString &file,const QCString &fontPath,bool checkResult, - const QCString &imageName = QCString()); + DotRunner(const QCString& baseName, const QCString& path, const QCString& md5Hash, + bool checkResult, const QCString &imageName = QCString()); /** Adds an additional job to the run. * Performing multiple jobs one file can be faster. @@ -409,19 +409,24 @@ class DotRunner bool run(); const CleanupItem &cleanup() const { return m_cleanupItem; } + DotConstString const& getBaseName() { return m_baseName; } + DotConstString const& getPath() { return m_path; } + DotConstString const& getMd5Hash() { return m_md5Hash; } + private: DotConstString m_dotExe; bool m_multiTargets; QList<DotConstString> m_jobs; DotConstString m_postArgs; DotConstString m_postCmd; - DotConstString m_file; + DotConstString m_baseName; DotConstString m_path; bool m_checkResult; DotConstString m_imageName; DotConstString m_imgExt; bool m_cleanUp; CleanupItem m_cleanupItem; + DotConstString m_md5Hash; }; /** Helper class to insert a set of map file into an output file */ @@ -497,6 +502,8 @@ class DotManager const QCString &figureNAme,const QCString &relPath); bool run(); + bool containsRun(const QCString& baseName, const QCString& path, const QCString& md5Hash); + private: DotManager(); virtual ~DotManager(); |