00001 #include <md5.h> 00002 00003 #include "dirdef.h" 00004 #include "filename.h" 00005 #include "doxygen.h" 00006 #include "util.h" 00007 #include "outputlist.h" 00008 #include "language.h" 00009 #include "message.h" 00010 #include "dot.h" 00011 00012 //---------------------------------------------------------------------- 00013 // method implementation 00014 00015 static int g_dirCount=0; 00016 00017 DirDef::DirDef(const char *path) : Definition(path,1,path) 00018 { 00019 // get display name (stipping the paths mentioned in STRIP_FROM_PATH) 00020 m_dispName = stripFromPath(path); 00021 // get short name (last part of path) 00022 m_shortName = path; 00023 if (m_shortName.at(m_shortName.length()-1)=='/') 00024 { // strip trailing / 00025 m_shortName = m_shortName.left(m_shortName.length()-1); 00026 } 00027 int pi=m_shortName.findRev('/'); 00028 if (pi!=-1) 00029 { // remove everything till the last / 00030 m_shortName = m_shortName.mid(pi+1); 00031 } 00032 setLocalName(m_shortName); 00033 00034 m_fileList = new FileList; 00035 m_usedDirs = new QDict<UsedDir>(257); 00036 m_usedDirs->setAutoDelete(TRUE); 00037 m_dirCount = g_dirCount++; 00038 m_level=-1; 00039 m_parent=0; 00040 } 00041 00042 DirDef::~DirDef() 00043 { 00044 delete m_fileList; 00045 delete m_usedDirs; 00046 } 00047 00048 bool DirDef::isLinkableInProject() const 00049 { 00050 return !isReference() && Config_getBool("SHOW_DIRECTORIES"); 00051 } 00052 00053 bool DirDef::isLinkable() const 00054 { 00055 return isReference() || isLinkableInProject(); 00056 } 00057 00058 void DirDef::addSubDir(DirDef *subdir) 00059 { 00060 m_subdirs.inSort(subdir); 00061 subdir->setOuterScope(this); 00062 subdir->m_parent=this; 00063 } 00064 00065 void DirDef::addFile(FileDef *fd) 00066 { 00067 m_fileList->inSort(fd); 00068 fd->setDirDef(this); 00069 } 00070 00071 static QCString encodeDirName(const QCString &anchor) 00072 { 00073 QCString result; 00074 00075 // convert to md5 hash 00076 uchar md5_sig[16]; 00077 QCString sigStr(33); 00078 MD5Buffer((const unsigned char *)anchor.data(),anchor.length(),md5_sig); 00079 MD5SigToString(md5_sig,sigStr.data(),33); 00080 return sigStr; 00081 00082 // old algorithm 00083 00084 // int l = anchor.length(),i; 00085 // for (i=0;i<l;i++) 00086 // { 00087 // char c = anchor.at(i); 00088 // if ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9')) 00089 // { 00090 // result+=c; 00091 // } 00092 // else 00093 // { 00094 // static char hexStr[]="0123456789ABCDEF"; 00095 // char escChar[]={ '_', 0, 0, 0 }; 00096 // escChar[1]=hexStr[c>>4]; 00097 // escChar[2]=hexStr[c&0xf]; 00098 // result+=escChar; 00099 // } 00100 // } 00101 // return result; 00102 } 00103 00104 QCString DirDef::getOutputFileBase() const 00105 { 00106 return "dir_"+encodeDirName(name()); 00107 //return QCString().sprintf("dir_%06d",m_dirCount); 00108 } 00109 00110 void DirDef::writeDetailedDocumentation(OutputList &ol) 00111 { 00112 if (!briefDescription().isEmpty() || !documentation().isEmpty()) 00113 { 00114 ol.writeRuler(); 00115 ol.pushGeneratorState(); 00116 ol.disable(OutputGenerator::Latex); 00117 ol.disable(OutputGenerator::RTF); 00118 ol.writeAnchor(0,"_details"); 00119 ol.popGeneratorState(); 00120 ol.startGroupHeader(); 00121 ol.parseText(theTranslator->trDetailedDescription()); 00122 ol.endGroupHeader(); 00123 00124 // repeat brief description 00125 if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF")) 00126 { 00127 ol.parseDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE); 00128 ol.newParagraph(); 00129 } 00130 00131 // write documentation 00132 if (!documentation().isEmpty()) 00133 { 00134 ol.parseDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE); 00135 } 00136 } 00137 } 00138 00139 void DirDef::writeDocumentation(OutputList &ol) 00140 { 00141 ol.pushGeneratorState(); 00142 00143 QCString shortTitle=theTranslator->trDirReference(m_shortName); 00144 QCString title=theTranslator->trDirReference(m_dispName); 00145 startFile(ol,getOutputFileBase(),name(),title,HLI_None,TRUE); 00146 00147 // write navigation path 00148 writeNavigationPath(ol); 00149 00150 ol.endQuickIndices(); 00151 ol.startContents(); 00152 00153 startTitle(ol,getOutputFileBase()); 00154 ol.pushGeneratorState(); 00155 ol.disableAllBut(OutputGenerator::Html); 00156 ol.parseText(shortTitle); 00157 ol.enableAll(); 00158 ol.disable(OutputGenerator::Html); 00159 ol.parseText(title); 00160 ol.popGeneratorState(); 00161 endTitle(ol,getOutputFileBase(),title); 00162 00163 // write brief or details (if DETAILS_AT_TOP) 00164 if (Config_getBool("DETAILS_AT_TOP")) 00165 { 00166 writeDetailedDocumentation(ol); 00167 ol.newParagraph(); 00168 } 00169 else if (!briefDescription().isEmpty()) 00170 { 00171 ol.parseDoc(briefFile(),briefLine(),this,0,briefDescription(),TRUE,FALSE); 00172 ol.writeString(" \n"); 00173 ol.pushGeneratorState(); 00174 ol.disable(OutputGenerator::Latex); 00175 ol.disable(OutputGenerator::RTF); 00176 ol.disable(OutputGenerator::Man); 00177 ol.startTextLink(0,"_details"); 00178 ol.parseText(theTranslator->trMore()); 00179 ol.endTextLink(); 00180 ol.enableAll(); 00181 ol.disableAllBut(OutputGenerator::Man); 00182 ol.newParagraph(); 00183 ol.popGeneratorState(); 00184 } 00185 00186 if (!Config_getString("GENERATE_TAGFILE").isEmpty()) 00187 { 00188 Doxygen::tagFile << " <compound kind=\"dir\">" << endl; 00189 Doxygen::tagFile << " <name>" << convertToXML(displayName()) << "</name>" << endl; 00190 Doxygen::tagFile << " <path>" << convertToXML(name()) << "</path>" << endl; 00191 Doxygen::tagFile << " <filename>" << convertToXML(getOutputFileBase()) << Doxygen::htmlFileExtension << "</filename>" << endl; 00192 } 00193 00194 // write graph dependency graph 00195 if (Config_getBool("DIRECTORY_GRAPH") && Config_getBool("HAVE_DOT")) 00196 { 00197 DotDirDeps dirDep(this); 00198 if (!dirDep.isTrivial()) 00199 { 00200 msg("Generating dependency graph for directory %s\n",displayName().data()); 00201 ol.disable(OutputGenerator::Man); 00202 ol.newParagraph(); 00203 ol.startDirDepGraph(); 00204 //TODO: ol.parseText(theTranslator->trDirDepGraph()); 00205 ol.endDirDepGraph(dirDep); 00206 ol.enableAll(); 00207 } 00208 } 00209 00210 ol.startMemberSections(); 00211 // write subdir list 00212 if (m_subdirs.count()>0) 00213 { 00214 ol.startMemberHeader(); 00215 ol.parseText(theTranslator->trDir(TRUE,FALSE)); 00216 ol.endMemberHeader(); 00217 ol.startMemberList(); 00218 DirDef *dd=m_subdirs.first(); 00219 while (dd) 00220 { 00221 ol.startMemberItem(0); 00222 ol.parseText(theTranslator->trDir(FALSE,TRUE)+" "); 00223 ol.insertMemberAlign(); 00224 ol.writeObjectLink(dd->getReference(),dd->getOutputFileBase(),0,dd->shortName()); 00225 ol.endMemberItem(); 00226 if (!Config_getString("GENERATE_TAGFILE").isEmpty()) 00227 { 00228 Doxygen::tagFile << " <dir>" << convertToXML(dd->displayName()) << "</dir>" << endl; 00229 } 00230 if (!dd->briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC")) 00231 { 00232 ol.startMemberDescription(); 00233 ol.parseDoc(briefFile(),briefLine(),dd,0,dd->briefDescription(), 00234 FALSE, // indexWords 00235 FALSE, // isExample 00236 0, // exampleName 00237 FALSE, // single line 00238 TRUE // link from index 00239 ); 00240 ol.endMemberDescription(); 00241 ol.newParagraph(); 00242 } 00243 dd=m_subdirs.next(); 00244 } 00245 00246 ol.endMemberList(); 00247 } 00248 00249 // write file list 00250 if (m_fileList->count()>0) 00251 { 00252 ol.startMemberHeader(); 00253 ol.parseText(theTranslator->trFile(TRUE,FALSE)); 00254 ol.endMemberHeader(); 00255 ol.startMemberList(); 00256 FileDef *fd=m_fileList->first(); 00257 while (fd) 00258 { 00259 ol.startMemberItem(0); 00260 ol.docify(theTranslator->trFile(FALSE,TRUE)+" "); 00261 ol.insertMemberAlign(); 00262 if (fd->isLinkable()) 00263 { 00264 ol.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0,fd->name()); 00265 } 00266 else 00267 { 00268 ol.startBold(); 00269 ol.docify(fd->name()); 00270 ol.endBold(); 00271 } 00272 if (fd->generateSourceFile()) 00273 { 00274 ol.pushGeneratorState(); 00275 ol.disableAllBut(OutputGenerator::Html); 00276 ol.docify(" "); 00277 ol.startTextLink(fd->includeName(),0); 00278 ol.docify("["); 00279 ol.parseText(theTranslator->trCode()); 00280 ol.docify("]"); 00281 ol.endTextLink(); 00282 ol.popGeneratorState(); 00283 } 00284 if (!Config_getString("GENERATE_TAGFILE").isEmpty()) 00285 { 00286 Doxygen::tagFile << " <file>" << convertToXML(fd->name()) << "</file>" << endl; 00287 } 00288 ol.endMemberItem(); 00289 if (!fd->briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC")) 00290 { 00291 ol.startMemberDescription(); 00292 ol.parseDoc(briefFile(),briefLine(),fd,0,fd->briefDescription(), 00293 FALSE, // indexWords 00294 FALSE, // isExample 00295 0, // exampleName 00296 FALSE, // single line 00297 TRUE // link from index 00298 ); 00299 ol.endMemberDescription(); 00300 ol.newParagraph(); 00301 } 00302 fd=m_fileList->next(); 00303 } 00304 ol.endMemberList(); 00305 } 00306 ol.endMemberSections(); 00307 00308 if (!Config_getString("GENERATE_TAGFILE").isEmpty()) 00309 { 00310 writeDocAnchorsToTagFile(); 00311 Doxygen::tagFile << " </compound>" << endl; 00312 } 00313 00314 00315 if (!Config_getBool("DETAILS_AT_TOP")) 00316 { 00317 writeDetailedDocumentation(ol); 00318 } 00319 00320 endFile(ol); 00321 ol.popGeneratorState(); 00322 } 00323 00324 #if 0 00325 void DirDef::writePathFragment(OutputList &ol) const 00326 { 00327 if (m_parent) 00328 { 00329 m_parent->writePathFragment(ol); 00330 ol.writeString(" / "); 00331 } 00332 ol.writeObjectLink(getReference(),getOutputFileBase(),0,shortName()); 00333 } 00334 00335 void DirDef::writeNavigationPath(OutputList &ol) 00336 { 00337 ol.pushGeneratorState(); 00338 ol.disableAllBut(OutputGenerator::Html); 00339 00340 ol.writeString("<div class=\"nav\">\n"); 00341 writePathFragment(ol); 00342 ol.writeString("</div>\n"); 00343 00344 ol.popGeneratorState(); 00345 } 00346 #endif 00347 00348 void DirDef::setLevel() 00349 { 00350 if (m_level==-1) // level not set before 00351 { 00352 DirDef *p = parent(); 00353 if (p) 00354 { 00355 p->setLevel(); 00356 m_level = p->level()+1; 00357 } 00358 else 00359 { 00360 m_level = 0; 00361 } 00362 } 00363 } 00364 00368 void DirDef::addUsesDependency(DirDef *dir,FileDef *srcFd, 00369 FileDef *dstFd,bool inherited) 00370 { 00371 if (this==dir) return; // do not add self-dependencies 00372 //static int count=0; 00373 //printf(" %d add dependency %s->%s due to %s->%s\n", 00374 // count++,shortName().data(), 00375 // dir->shortName().data(), 00376 // srcFd->name().data(), 00377 // dstFd->name().data()); 00378 00379 // levels match => add direct dependency 00380 bool added=FALSE; 00381 UsedDir *usedDir = m_usedDirs->find(dir->getOutputFileBase()); 00382 if (usedDir) // dir dependency already present 00383 { 00384 FilePair *usedPair = usedDir->findFilePair( 00385 srcFd->getOutputFileBase()+dstFd->getOutputFileBase()); 00386 if (usedPair==0) // new file dependency 00387 { 00388 //printf(" => new file\n"); 00389 usedDir->addFileDep(srcFd,dstFd); 00390 added=TRUE; 00391 } 00392 else 00393 { 00394 // dir & file dependency already added 00395 } 00396 } 00397 else // new directory dependency 00398 { 00399 //printf(" => new file\n"); 00400 usedDir = new UsedDir(dir,inherited); 00401 usedDir->addFileDep(srcFd,dstFd); 00402 m_usedDirs->insert(dir->getOutputFileBase(),usedDir); 00403 added=TRUE; 00404 } 00405 if (added) 00406 { 00407 if (dir->parent()) 00408 { 00409 // add relation to parent of used dir 00410 addUsesDependency(dir->parent(),srcFd,dstFd,inherited); 00411 } 00412 if (parent()) 00413 { 00414 // add relation for the parent of this dir as well 00415 parent()->addUsesDependency(dir,srcFd,dstFd,TRUE); 00416 } 00417 } 00418 } 00419 00422 void DirDef::computeDependencies() 00423 { 00424 FileList *fl = m_fileList; 00425 if (fl) 00426 { 00427 QListIterator<FileDef> fli(*fl); 00428 FileDef *fd; 00429 for (fli.toFirst();(fd=fli.current());++fli) // foreach file in dir dd 00430 { 00431 //printf(" File %s\n",fd->name().data()); 00432 //printf("** dir=%s file=%s\n",shortName().data(),fd->name().data()); 00433 QList<IncludeInfo> *ifl = fd->includeFileList(); 00434 if (ifl) 00435 { 00436 QListIterator<IncludeInfo> ifli(*ifl); 00437 IncludeInfo *ii; 00438 for (ifli.toFirst();(ii=ifli.current());++ifli) // foreach include file 00439 { 00440 //printf(" > %s\n",ii->includeName.data()); 00441 //printf(" #include %s\n",ii->includeName.data()); 00442 if (ii->fileDef && ii->fileDef->isLinkable()) // linkable file 00443 { 00444 DirDef *usedDir = ii->fileDef->getDirDef(); 00445 if (usedDir) 00446 { 00447 // add dependency: thisDir->usedDir 00448 //static int count=0; 00449 //printf(" %d: add dependency %s->%s\n",count++,name().data(),usedDir->name().data()); 00450 addUsesDependency(usedDir,fd,ii->fileDef,FALSE); 00451 } 00452 } 00453 } 00454 } 00455 } 00456 } 00457 } 00458 00459 bool DirDef::isParentOf(DirDef *dir) const 00460 { 00461 if (dir->parent()==this) // this is a parent of dir 00462 return TRUE; 00463 else if (dir->parent()) // repeat for the parent of dir 00464 return isParentOf(dir->parent()); 00465 else 00466 return FALSE; 00467 } 00468 00469 bool DirDef::depGraphIsTrivial() const 00470 { 00471 return FALSE; 00472 } 00473 00474 //---------------------------------------------------------------------- 00475 00476 int FilePairDict::compareItems(GCI item1,GCI item2) 00477 { 00478 FilePair *left = (FilePair*)item1; 00479 FilePair *right = (FilePair*)item2; 00480 int orderHi = stricmp(left->source()->name(),right->source()->name()); 00481 int orderLo = stricmp(left->destination()->name(),right->destination()->name()); 00482 return orderHi==0 ? orderLo : orderHi; 00483 } 00484 00485 //---------------------------------------------------------------------- 00486 00487 UsedDir::UsedDir(DirDef *dir,bool inherited) : 00488 m_dir(dir), m_filePairs(7), m_inherited(inherited) 00489 { 00490 m_filePairs.setAutoDelete(TRUE); 00491 } 00492 00493 UsedDir::~UsedDir() 00494 { 00495 } 00496 00497 00498 void UsedDir::addFileDep(FileDef *srcFd,FileDef *dstFd) 00499 { 00500 m_filePairs.inSort(srcFd->getOutputFileBase()+dstFd->getOutputFileBase(), 00501 new FilePair(srcFd,dstFd)); 00502 } 00503 00504 FilePair *UsedDir::findFilePair(const char *name) 00505 { 00506 QCString n=name; 00507 return n.isEmpty() ? 0 : m_filePairs.find(n); 00508 } 00509 00510 DirDef *DirDef::createNewDir(const char *path) 00511 { 00512 ASSERT(path!=0); 00513 DirDef *dir = Doxygen::directories->find(path); 00514 if (dir==0) // new dir 00515 { 00516 //printf("Adding new dir %s\n",path); 00517 dir = new DirDef(path); 00518 //printf("createNewDir %s short=%s\n",path,dir->shortName().data()); 00519 Doxygen::directories->inSort(path,dir); 00520 } 00521 return dir; 00522 } 00523 00524 bool DirDef::matchPath(const QCString &path,QStrList &l) 00525 { 00526 const char *s=l.first(); 00527 while (s) 00528 { 00529 QCString prefix = s; 00530 if (stricmp(prefix.left(path.length()),path)==0) // case insensitive compare 00531 { 00532 return TRUE; 00533 } 00534 s = l.next(); 00535 } 00536 return FALSE; 00537 } 00538 00542 DirDef *DirDef::mergeDirectoryInTree(const QCString &path) 00543 { 00544 //printf("DirDef::mergeDirectoryInTree(%s)\n",path.data()); 00545 int p=0,i=0; 00546 DirDef *dir=0; 00547 while ((i=path.find('/',p))!=-1) 00548 { 00549 QCString part=path.left(i+1); 00550 if (!matchPath(part,Config_getList("STRIP_FROM_PATH")) && part!="/") 00551 { 00552 dir=createNewDir(part); 00553 } 00554 p=i+1; 00555 } 00556 return dir; 00557 } 00558 00559 void DirDef::writeDepGraph(QTextStream &t) 00560 { 00561 writeDotDirDepGraph(t,this); 00562 } 00563 00564 //---------------------------------------------------------------------- 00565 00566 static void writePartialDirPath(OutputList &ol,const DirDef *root,const DirDef *target) 00567 { 00568 if (target->parent()!=root) 00569 { 00570 writePartialDirPath(ol,root,target->parent()); 00571 ol.writeString(" / "); 00572 } 00573 ol.writeObjectLink(target->getReference(),target->getOutputFileBase(),0,target->shortName()); 00574 } 00575 00576 static void writePartialFilePath(OutputList &ol,const DirDef *root,const FileDef *fd) 00577 { 00578 if (fd->getDirDef() && fd->getDirDef()!=root) 00579 { 00580 writePartialDirPath(ol,root,fd->getDirDef()); 00581 ol.writeString(" / "); 00582 } 00583 if (fd->isLinkable()) 00584 { 00585 ol.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0,fd->name()); 00586 } 00587 else 00588 { 00589 ol.startBold(); 00590 ol.docify(fd->name()); 00591 ol.endBold(); 00592 } 00593 } 00594 00595 void DirRelation::writeDocumentation(OutputList &ol) 00596 { 00597 ol.pushGeneratorState(); 00598 ol.disableAllBut(OutputGenerator::Html); 00599 00600 QCString shortTitle=m_src->shortName()+" → "+ 00601 m_dst->dir()->shortName()+" Relation";//theTranslator->trDirRelation(m_shortName); 00602 QCString title=m_src->displayName()+" -> "+ 00603 m_dst->dir()->shortName()+" Relation";//theTranslator->trDirRelation(m_dispName); 00604 startFile(ol,getOutputFileBase(),getOutputFileBase(),title); 00605 00606 // write navigation path 00607 m_src->writeNavigationPath(ol); 00608 00609 //startTitle(ol,getOutputFileBase()); 00610 // ol.parseText(shortTitle); 00611 //endTitle(ol,getOutputFileBase(),title); 00612 ol.writeString("<h3>"+shortTitle+"</h3>"); 00613 00614 ol.writeString("<table class=\"dirtab\">"); 00615 ol.writeString("<tr class=\"dirtab\">"); 00616 ol.writeString("<th class=\"dirtab\">File in "); 00617 m_src->writePathFragment(ol); 00618 ol.writeString("</th>"); 00619 ol.writeString("<th class=\"dirtab\">Includes file in "); 00620 m_dst->dir()->writePathFragment(ol); 00621 ol.writeString("</th>"); 00622 ol.writeString("</tr>"); 00623 00624 SDict<FilePair>::Iterator fpi(m_dst->filePairs()); 00625 FilePair *fp; 00626 for (fpi.toFirst();(fp=fpi.current());++fpi) 00627 { 00628 ol.writeString("<tr class=\"dirtab\">"); 00629 ol.writeString("<td class=\"dirtab\">"); 00630 writePartialFilePath(ol,m_src,fp->source()); 00631 ol.writeString("</td>"); 00632 ol.writeString("<td class=\"dirtab\">"); 00633 writePartialFilePath(ol,m_dst->dir(),fp->destination()); 00634 ol.writeString("</td>"); 00635 ol.writeString("</tr>"); 00636 } 00637 ol.writeString("</table>"); 00638 00639 endFile(ol); 00640 ol.popGeneratorState(); 00641 } 00642 00643 //---------------------------------------------------------------------- 00644 // external functions 00645 00646 void buildDirectories() 00647 { 00648 // for each input file 00649 FileNameListIterator fnli(*Doxygen::inputNameList); 00650 FileName *fn; 00651 for (fnli.toFirst();(fn=fnli.current());++fnli) 00652 { 00653 FileNameIterator fni(*fn); 00654 FileDef *fd; 00655 for (;(fd=fni.current());++fni) 00656 { 00657 //printf("buildDirectories %s\n",fd->name().data()); 00658 if (fd->getReference().isEmpty() && !fd->isDocumentationFile()) 00659 { 00660 DirDef *dir; 00661 if ((dir=Doxygen::directories->find(fd->getPath()))==0) // new directory 00662 { 00663 dir = DirDef::mergeDirectoryInTree(fd->getPath()); 00664 } 00665 if (dir) dir->addFile(fd); 00666 } 00667 else 00668 { 00669 // do something for file imported via tag files. 00670 } 00671 } 00672 } 00673 00674 //DirDef *root = new DirDef("root:"); 00675 // compute relations between directories => introduce container dirs. 00676 DirDef *dir; 00677 DirSDict::Iterator sdi(*Doxygen::directories); 00678 for (sdi.toFirst();(dir=sdi.current());++sdi) 00679 { 00680 //printf("New dir %s\n",dir->displayName().data()); 00681 QCString name = dir->name(); 00682 int i=name.findRev('/',name.length()-2); 00683 if (i>0) 00684 { 00685 DirDef *parent = Doxygen::directories->find(name.left(i+1)); 00686 //if (parent==0) parent=root; 00687 if (parent) 00688 { 00689 parent->addSubDir(dir); 00690 //printf("DirDef::addSubdir(): Adding subdir\n%s to\n%s\n", 00691 // dir->displayName().data(), parent->displayName().data()); 00692 } 00693 } 00694 } 00695 } 00696 00697 void computeDirDependencies() 00698 { 00699 DirDef *dir; 00700 DirSDict::Iterator sdi(*Doxygen::directories); 00701 // compute nesting level for each directory 00702 for (sdi.toFirst();(dir=sdi.current());++sdi) 00703 { 00704 dir->setLevel(); 00705 } 00706 // compute uses dependencies between directories 00707 for (sdi.toFirst();(dir=sdi.current());++sdi) 00708 { 00709 //printf("computeDependencies for %s: #dirs=%d\n",dir->name().data(),Doxygen::directories.count()); 00710 dir->computeDependencies(); 00711 } 00712 00713 #if 0 00714 printf("-------------------------------------------------------------\n"); 00715 // print dependencies (for debugging) 00716 for (sdi.toFirst();(dir=sdi.current());++sdi) 00717 { 00718 if (dir->usedDirs()) 00719 { 00720 QDictIterator<UsedDir> udi(*dir->usedDirs()); 00721 UsedDir *usedDir; 00722 for (udi.toFirst();(usedDir=udi.current());++udi) 00723 { 00724 printf("%s depends on %s due to ", 00725 dir->shortName().data(),usedDir->dir()->shortName().data()); 00726 QDictIterator<FileDef> fdi(usedDir->files()); 00727 FileDef *fd; 00728 for (fdi.toFirst();(fd=fdi.current());++fdi) 00729 { 00730 printf("%s ",fd->name().data()); 00731 } 00732 printf("\n"); 00733 } 00734 } 00735 } 00736 printf("^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^\n"); 00737 #endif 00738 } 00739 00740 00741 void writeDirDependencyGraph(const char *dirName) 00742 { 00743 QString path; 00744 DirDef *dir; 00745 DirSDict::Iterator sdi(*Doxygen::directories); 00746 QFile htmlPage(QCString(dirName)+"/dirdeps.html"); 00747 if (htmlPage.open(IO_WriteOnly)) 00748 { 00749 QTextStream out(&htmlPage); 00750 out << "<html><body>"; 00751 for (sdi.toFirst();(dir=sdi.current());++sdi) 00752 { 00753 path=dirName; 00754 path+="/"; 00755 path+=dir->getOutputFileBase(); 00756 path+="_dep.dot"; 00757 out << "<h4>" << dir->displayName() << "</h4>" << endl; 00758 out << "<img src=\"" << dir->getOutputFileBase() << "_dep.gif\">" << endl; 00759 QFile f(path); 00760 if (f.open(IO_WriteOnly)) 00761 { 00762 QTextStream t(&f); 00763 dir->writeDepGraph(t); 00764 } 00765 f.close(); 00766 00767 QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); 00768 QCString outFile = QCString(dirName)+"/"+ 00769 dir->getOutputFileBase()+"_dep."+imgExt; 00770 DotRunner dotRun(path); 00771 dotRun.addJob(imgExt,outFile); 00772 dotRun.run(); 00773 00774 //QCString dotArgs(4096); 00775 //dotArgs.sprintf("%s -Tgif -o %s",path.data(),outFile.data()); 00776 //if (portable_system(Config_getString("DOT_PATH")+"dot",dotArgs,FALSE)!=0) 00777 //{ 00778 // err("Problems running dot. Check your installation!\n"); 00779 //} 00780 } 00781 out << "</body></html>"; 00782 } 00783 htmlPage.close(); 00784 } 00785 00786 void generateDirDocs(OutputList &ol) 00787 { 00788 DirDef *dir; 00789 DirSDict::Iterator sdi(*Doxygen::directories); 00790 for (sdi.toFirst();(dir=sdi.current());++sdi) 00791 { 00792 dir->writeDocumentation(ol); 00793 } 00794 if (Config_getBool("DIRECTORY_GRAPH")) 00795 { 00796 SDict<DirRelation>::Iterator rdi(Doxygen::dirRelations); 00797 DirRelation *dr; 00798 for (rdi.toFirst();(dr=rdi.current());++rdi) 00799 { 00800 dr->writeDocumentation(ol); 00801 } 00802 } 00803 } 00804