|
1 #include <md5.h> |
|
2 |
|
3 #include "dirdef.h" |
|
4 #include "filename.h" |
|
5 #include "doxygen.h" |
|
6 #include "util.h" |
|
7 #include "outputlist.h" |
|
8 #include "language.h" |
|
9 #include "message.h" |
|
10 #include "dot.h" |
|
11 #include "layout.h" |
|
12 |
|
13 //---------------------------------------------------------------------- |
|
14 // method implementation |
|
15 |
|
16 static int g_dirCount=0; |
|
17 |
|
18 DirDef::DirDef(const char *path) : Definition(path,1,path) |
|
19 { |
|
20 // get display name (stipping the paths mentioned in STRIP_FROM_PATH) |
|
21 m_dispName = stripFromPath(path); |
|
22 // get short name (last part of path) |
|
23 m_shortName = path; |
|
24 if (m_shortName.at(m_shortName.length()-1)=='/') |
|
25 { // strip trailing / |
|
26 m_shortName = m_shortName.left(m_shortName.length()-1); |
|
27 } |
|
28 int pi=m_shortName.findRev('/'); |
|
29 if (pi!=-1) |
|
30 { // remove everything till the last / |
|
31 m_shortName = m_shortName.mid(pi+1); |
|
32 } |
|
33 setLocalName(m_shortName); |
|
34 |
|
35 m_fileList = new FileList; |
|
36 m_usedDirs = new QDict<UsedDir>(257); |
|
37 m_usedDirs->setAutoDelete(TRUE); |
|
38 m_dirCount = g_dirCount++; |
|
39 m_level=-1; |
|
40 m_parent=0; |
|
41 } |
|
42 |
|
43 DirDef::~DirDef() |
|
44 { |
|
45 delete m_fileList; |
|
46 delete m_usedDirs; |
|
47 } |
|
48 |
|
49 bool DirDef::isLinkableInProject() const |
|
50 { |
|
51 return !isReference() && Config_getBool("SHOW_DIRECTORIES"); |
|
52 } |
|
53 |
|
54 bool DirDef::isLinkable() const |
|
55 { |
|
56 return isReference() || isLinkableInProject(); |
|
57 } |
|
58 |
|
59 void DirDef::addSubDir(DirDef *subdir) |
|
60 { |
|
61 m_subdirs.inSort(subdir); |
|
62 subdir->setOuterScope(this); |
|
63 subdir->m_parent=this; |
|
64 } |
|
65 |
|
66 void DirDef::addFile(FileDef *fd) |
|
67 { |
|
68 m_fileList->inSort(fd); |
|
69 fd->setDirDef(this); |
|
70 } |
|
71 |
|
72 static QCString encodeDirName(const QCString &anchor) |
|
73 { |
|
74 QCString result; |
|
75 |
|
76 // convert to md5 hash |
|
77 uchar md5_sig[16]; |
|
78 QCString sigStr(33); |
|
79 MD5Buffer((const unsigned char *)anchor.data(),anchor.length(),md5_sig); |
|
80 MD5SigToString(md5_sig,sigStr.data(),33); |
|
81 return sigStr; |
|
82 |
|
83 // old algorithm |
|
84 |
|
85 // int l = anchor.length(),i; |
|
86 // for (i=0;i<l;i++) |
|
87 // { |
|
88 // char c = anchor.at(i); |
|
89 // if ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9')) |
|
90 // { |
|
91 // result+=c; |
|
92 // } |
|
93 // else |
|
94 // { |
|
95 // static char hexStr[]="0123456789ABCDEF"; |
|
96 // char escChar[]={ '_', 0, 0, 0 }; |
|
97 // escChar[1]=hexStr[c>>4]; |
|
98 // escChar[2]=hexStr[c&0xf]; |
|
99 // result+=escChar; |
|
100 // } |
|
101 // } |
|
102 // return result; |
|
103 } |
|
104 |
|
105 QCString DirDef::getOutputFileBase() const |
|
106 { |
|
107 return "dir_"+encodeDirName(name()); |
|
108 //return QCString().sprintf("dir_%06d",m_dirCount); |
|
109 } |
|
110 |
|
111 void DirDef::writeDetailedDescription(OutputList &ol,const QCString &title) |
|
112 { |
|
113 if ((!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF")) || |
|
114 !documentation().isEmpty()) |
|
115 { |
|
116 ol.writeRuler(); |
|
117 ol.pushGeneratorState(); |
|
118 ol.disableAllBut(OutputGenerator::Html); |
|
119 ol.writeAnchor(0,"_details"); |
|
120 ol.popGeneratorState(); |
|
121 ol.startGroupHeader(); |
|
122 ol.parseText(title); |
|
123 ol.endGroupHeader(); |
|
124 |
|
125 // repeat brief description |
|
126 if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF")) |
|
127 { |
|
128 ol.parseDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE); |
|
129 } |
|
130 // separator between brief and details |
|
131 if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF") && |
|
132 !documentation().isEmpty()) |
|
133 { |
|
134 ol.pushGeneratorState(); |
|
135 ol.disable(OutputGenerator::Man); |
|
136 ol.disable(OutputGenerator::RTF); |
|
137 // ol.newParagraph(); // FIXME:PARA |
|
138 ol.enableAll(); |
|
139 ol.disableAllBut(OutputGenerator::Man); |
|
140 ol.writeString("\n\n"); |
|
141 ol.popGeneratorState(); |
|
142 } |
|
143 |
|
144 // write documentation |
|
145 if (!documentation().isEmpty()) |
|
146 { |
|
147 ol.parseDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE); |
|
148 } |
|
149 } |
|
150 } |
|
151 |
|
152 void DirDef::writeBriefDescription(OutputList &ol) |
|
153 { |
|
154 if (!briefDescription().isEmpty()) |
|
155 { |
|
156 ol.startParagraph(); |
|
157 ol.parseDoc(briefFile(),briefLine(),this,0,briefDescription(),TRUE,FALSE); |
|
158 ol.pushGeneratorState(); |
|
159 ol.disable(OutputGenerator::RTF); |
|
160 ol.writeString(" \n"); |
|
161 ol.enable(OutputGenerator::RTF); |
|
162 |
|
163 if (Config_getBool("REPEAT_BRIEF") || |
|
164 !documentation().isEmpty() |
|
165 ) |
|
166 { |
|
167 ol.disableAllBut(OutputGenerator::Html); |
|
168 ol.startTextLink(0,"_details"); |
|
169 ol.parseText(theTranslator->trMore()); |
|
170 ol.endTextLink(); |
|
171 } |
|
172 ol.popGeneratorState(); |
|
173 |
|
174 //ol.pushGeneratorState(); |
|
175 //ol.disable(OutputGenerator::RTF); |
|
176 //ol.newParagraph(); |
|
177 //ol.popGeneratorState(); |
|
178 ol.endParagraph(); |
|
179 } |
|
180 ol.writeSynopsis(); |
|
181 } |
|
182 |
|
183 void DirDef::writeDirectoryGraph(OutputList &ol) |
|
184 { |
|
185 // write graph dependency graph |
|
186 if (/*Config_getBool("DIRECTORY_GRAPH") &&*/ Config_getBool("HAVE_DOT")) |
|
187 { |
|
188 DotDirDeps dirDep(this); |
|
189 if (!dirDep.isTrivial()) |
|
190 { |
|
191 msg("Generating dependency graph for directory %s\n",displayName().data()); |
|
192 ol.disable(OutputGenerator::Man); |
|
193 ol.startParagraph(); |
|
194 ol.startDirDepGraph(); |
|
195 //TODO: ol.parseText(theTranslator->trDirDepGraph()); |
|
196 ol.endDirDepGraph(dirDep); |
|
197 ol.endParagraph(); |
|
198 ol.enableAll(); |
|
199 } |
|
200 } |
|
201 } |
|
202 |
|
203 void DirDef::writeSubDirList(OutputList &ol) |
|
204 { |
|
205 // write subdir list |
|
206 if (m_subdirs.count()>0) |
|
207 { |
|
208 ol.startMemberHeader(); |
|
209 ol.parseText(theTranslator->trDir(TRUE,FALSE)); |
|
210 ol.endMemberHeader(); |
|
211 ol.startMemberList(); |
|
212 DirDef *dd=m_subdirs.first(); |
|
213 while (dd) |
|
214 { |
|
215 ol.startMemberItem(0); |
|
216 ol.parseText(theTranslator->trDir(FALSE,TRUE)+" "); |
|
217 ol.insertMemberAlign(); |
|
218 ol.writeObjectLink(dd->getReference(),dd->getOutputFileBase(),0,dd->shortName()); |
|
219 ol.endMemberItem(); |
|
220 if (!Config_getString("GENERATE_TAGFILE").isEmpty()) |
|
221 { |
|
222 Doxygen::tagFile << " <dir>" << convertToXML(dd->displayName()) << "</dir>" << endl; |
|
223 } |
|
224 if (!dd->briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC")) |
|
225 { |
|
226 ol.startParagraph(); |
|
227 ol.startMemberDescription(); |
|
228 ol.parseDoc(briefFile(),briefLine(),dd,0,dd->briefDescription(), |
|
229 FALSE, // indexWords |
|
230 FALSE, // isExample |
|
231 0, // exampleName |
|
232 FALSE, // single line |
|
233 TRUE // link from index |
|
234 ); |
|
235 ol.endMemberDescription(); |
|
236 ol.endParagraph(); |
|
237 } |
|
238 dd=m_subdirs.next(); |
|
239 } |
|
240 |
|
241 ol.endMemberList(); |
|
242 } |
|
243 } |
|
244 |
|
245 void DirDef::writeFileList(OutputList &ol) |
|
246 { |
|
247 // write file list |
|
248 if (m_fileList->count()>0) |
|
249 { |
|
250 ol.startMemberHeader(); |
|
251 ol.parseText(theTranslator->trFile(TRUE,FALSE)); |
|
252 ol.endMemberHeader(); |
|
253 ol.startMemberList(); |
|
254 FileDef *fd=m_fileList->first(); |
|
255 while (fd) |
|
256 { |
|
257 ol.startMemberItem(0); |
|
258 ol.docify(theTranslator->trFile(FALSE,TRUE)+" "); |
|
259 ol.insertMemberAlign(); |
|
260 if (fd->isLinkable()) |
|
261 { |
|
262 ol.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0,fd->name()); |
|
263 } |
|
264 else |
|
265 { |
|
266 ol.startBold(); |
|
267 ol.docify(fd->name()); |
|
268 ol.endBold(); |
|
269 } |
|
270 if (fd->generateSourceFile()) |
|
271 { |
|
272 ol.pushGeneratorState(); |
|
273 ol.disableAllBut(OutputGenerator::Html); |
|
274 ol.docify(" "); |
|
275 ol.startTextLink(fd->includeName(),0); |
|
276 ol.docify("["); |
|
277 ol.parseText(theTranslator->trCode()); |
|
278 ol.docify("]"); |
|
279 ol.endTextLink(); |
|
280 ol.popGeneratorState(); |
|
281 } |
|
282 if (!Config_getString("GENERATE_TAGFILE").isEmpty()) |
|
283 { |
|
284 Doxygen::tagFile << " <file>" << convertToXML(fd->name()) << "</file>" << endl; |
|
285 } |
|
286 ol.endMemberItem(); |
|
287 if (!fd->briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC")) |
|
288 { |
|
289 ol.startParagraph(); |
|
290 ol.startMemberDescription(); |
|
291 ol.parseDoc(briefFile(),briefLine(),fd,0,fd->briefDescription(), |
|
292 FALSE, // indexWords |
|
293 FALSE, // isExample |
|
294 0, // exampleName |
|
295 FALSE, // single line |
|
296 TRUE // link from index |
|
297 ); |
|
298 ol.endMemberDescription(); |
|
299 ol.endParagraph(); |
|
300 } |
|
301 fd=m_fileList->next(); |
|
302 } |
|
303 ol.endMemberList(); |
|
304 } |
|
305 } |
|
306 |
|
307 void DirDef::startMemberDeclarations(OutputList &ol) |
|
308 { |
|
309 ol.startMemberSections(); |
|
310 } |
|
311 |
|
312 void DirDef::endMemberDeclarations(OutputList &ol) |
|
313 { |
|
314 ol.endMemberSections(); |
|
315 } |
|
316 |
|
317 void DirDef::writeDocumentation(OutputList &ol) |
|
318 { |
|
319 ol.pushGeneratorState(); |
|
320 |
|
321 QCString shortTitle=theTranslator->trDirReference(m_shortName); |
|
322 QCString title=theTranslator->trDirReference(m_dispName); |
|
323 startFile(ol,getOutputFileBase(),name(),title,HLI_None,TRUE); |
|
324 |
|
325 // write navigation path |
|
326 writeNavigationPath(ol); |
|
327 |
|
328 ol.endQuickIndices(); |
|
329 ol.startContents(); |
|
330 |
|
331 startTitle(ol,getOutputFileBase()); |
|
332 ol.pushGeneratorState(); |
|
333 ol.disableAllBut(OutputGenerator::Html); |
|
334 ol.parseText(shortTitle); |
|
335 ol.enableAll(); |
|
336 ol.disable(OutputGenerator::Html); |
|
337 ol.parseText(title); |
|
338 ol.popGeneratorState(); |
|
339 endTitle(ol,getOutputFileBase(),title); |
|
340 |
|
341 if (!Config_getString("GENERATE_TAGFILE").isEmpty()) |
|
342 { |
|
343 Doxygen::tagFile << " <compound kind=\"dir\">" << endl; |
|
344 Doxygen::tagFile << " <name>" << convertToXML(displayName()) << "</name>" << endl; |
|
345 Doxygen::tagFile << " <path>" << convertToXML(name()) << "</path>" << endl; |
|
346 Doxygen::tagFile << " <filename>" << convertToXML(getOutputFileBase()) << Doxygen::htmlFileExtension << "</filename>" << endl; |
|
347 } |
|
348 |
|
349 //---------------------------------------- start flexible part ------------------------------- |
|
350 |
|
351 QListIterator<LayoutDocEntry> eli( |
|
352 LayoutDocManager::instance().docEntries(LayoutDocManager::Directory)); |
|
353 LayoutDocEntry *lde; |
|
354 for (eli.toFirst();(lde=eli.current());++eli) |
|
355 { |
|
356 switch (lde->kind()) |
|
357 { |
|
358 case LayoutDocEntry::BriefDesc: |
|
359 writeBriefDescription(ol); |
|
360 break; |
|
361 case LayoutDocEntry::DirGraph: |
|
362 writeDirectoryGraph(ol); |
|
363 break; |
|
364 case LayoutDocEntry::MemberDeclStart: |
|
365 startMemberDeclarations(ol); |
|
366 break; |
|
367 case LayoutDocEntry::DirSubDirs: |
|
368 writeSubDirList(ol); |
|
369 break; |
|
370 case LayoutDocEntry::DirFiles: |
|
371 writeFileList(ol); |
|
372 break; |
|
373 case LayoutDocEntry::MemberDeclEnd: |
|
374 endMemberDeclarations(ol); |
|
375 break; |
|
376 case LayoutDocEntry::DetailedDesc: |
|
377 { |
|
378 LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde; |
|
379 writeDetailedDescription(ol,ls->title); |
|
380 } |
|
381 break; |
|
382 case LayoutDocEntry::ClassIncludes: |
|
383 case LayoutDocEntry::ClassInheritanceGraph: |
|
384 case LayoutDocEntry::ClassNestedClasses: |
|
385 case LayoutDocEntry::ClassCollaborationGraph: |
|
386 case LayoutDocEntry::ClassAllMembersLink: |
|
387 case LayoutDocEntry::ClassUsedFiles: |
|
388 case LayoutDocEntry::NamespaceNestedNamespaces: |
|
389 case LayoutDocEntry::NamespaceClasses: |
|
390 case LayoutDocEntry::FileClasses: |
|
391 case LayoutDocEntry::FileNamespaces: |
|
392 case LayoutDocEntry::FileIncludes: |
|
393 case LayoutDocEntry::FileIncludeGraph: |
|
394 case LayoutDocEntry::FileIncludedByGraph: |
|
395 case LayoutDocEntry::FileSourceLink: |
|
396 case LayoutDocEntry::GroupClasses: |
|
397 case LayoutDocEntry::GroupNamespaces: |
|
398 case LayoutDocEntry::GroupDirs: |
|
399 case LayoutDocEntry::GroupNestedGroups: |
|
400 case LayoutDocEntry::GroupFiles: |
|
401 case LayoutDocEntry::GroupGraph: |
|
402 case LayoutDocEntry::GroupPageDocs: |
|
403 case LayoutDocEntry::AuthorSection: |
|
404 case LayoutDocEntry::MemberGroups: |
|
405 case LayoutDocEntry::MemberDecl: |
|
406 case LayoutDocEntry::MemberDef: |
|
407 case LayoutDocEntry::MemberDefStart: |
|
408 case LayoutDocEntry::MemberDefEnd: |
|
409 err("Internal inconsistency: member %d should not be part of " |
|
410 "LayoutDocManager::Directory entry list\n",lde->kind()); |
|
411 break; |
|
412 } |
|
413 } |
|
414 |
|
415 //---------------------------------------- end flexible part ------------------------------- |
|
416 |
|
417 if (!Config_getString("GENERATE_TAGFILE").isEmpty()) |
|
418 { |
|
419 writeDocAnchorsToTagFile(); |
|
420 Doxygen::tagFile << " </compound>" << endl; |
|
421 } |
|
422 |
|
423 endFile(ol); |
|
424 ol.popGeneratorState(); |
|
425 |
|
426 |
|
427 } |
|
428 |
|
429 #if 0 |
|
430 void DirDef::writePathFragment(OutputList &ol) const |
|
431 { |
|
432 if (m_parent) |
|
433 { |
|
434 m_parent->writePathFragment(ol); |
|
435 ol.writeString(" / "); |
|
436 } |
|
437 ol.writeObjectLink(getReference(),getOutputFileBase(),0,shortName()); |
|
438 } |
|
439 |
|
440 void DirDef::writeNavigationPath(OutputList &ol) |
|
441 { |
|
442 ol.pushGeneratorState(); |
|
443 ol.disableAllBut(OutputGenerator::Html); |
|
444 |
|
445 ol.writeString("<div class=\"nav\">\n"); |
|
446 writePathFragment(ol); |
|
447 ol.writeString("</div>\n"); |
|
448 |
|
449 ol.popGeneratorState(); |
|
450 } |
|
451 #endif |
|
452 |
|
453 void DirDef::setLevel() |
|
454 { |
|
455 if (m_level==-1) // level not set before |
|
456 { |
|
457 DirDef *p = parent(); |
|
458 if (p) |
|
459 { |
|
460 p->setLevel(); |
|
461 m_level = p->level()+1; |
|
462 } |
|
463 else |
|
464 { |
|
465 m_level = 0; |
|
466 } |
|
467 } |
|
468 } |
|
469 |
|
470 /** Add as "uses" dependency between \a this dir and \a dir, |
|
471 * that was caused by a dependency on file \a fd. |
|
472 */ |
|
473 void DirDef::addUsesDependency(DirDef *dir,FileDef *srcFd, |
|
474 FileDef *dstFd,bool inherited) |
|
475 { |
|
476 if (this==dir) return; // do not add self-dependencies |
|
477 //static int count=0; |
|
478 //printf(" %d add dependency %s->%s due to %s->%s\n", |
|
479 // count++,shortName().data(), |
|
480 // dir->shortName().data(), |
|
481 // srcFd->name().data(), |
|
482 // dstFd->name().data()); |
|
483 |
|
484 // levels match => add direct dependency |
|
485 bool added=FALSE; |
|
486 UsedDir *usedDir = m_usedDirs->find(dir->getOutputFileBase()); |
|
487 if (usedDir) // dir dependency already present |
|
488 { |
|
489 FilePair *usedPair = usedDir->findFilePair( |
|
490 srcFd->getOutputFileBase()+dstFd->getOutputFileBase()); |
|
491 if (usedPair==0) // new file dependency |
|
492 { |
|
493 //printf(" => new file\n"); |
|
494 usedDir->addFileDep(srcFd,dstFd); |
|
495 added=TRUE; |
|
496 } |
|
497 else |
|
498 { |
|
499 // dir & file dependency already added |
|
500 } |
|
501 } |
|
502 else // new directory dependency |
|
503 { |
|
504 //printf(" => new file\n"); |
|
505 usedDir = new UsedDir(dir,inherited); |
|
506 usedDir->addFileDep(srcFd,dstFd); |
|
507 m_usedDirs->insert(dir->getOutputFileBase(),usedDir); |
|
508 added=TRUE; |
|
509 } |
|
510 if (added) |
|
511 { |
|
512 if (dir->parent()) |
|
513 { |
|
514 // add relation to parent of used dir |
|
515 addUsesDependency(dir->parent(),srcFd,dstFd,inherited); |
|
516 } |
|
517 if (parent()) |
|
518 { |
|
519 // add relation for the parent of this dir as well |
|
520 parent()->addUsesDependency(dir,srcFd,dstFd,TRUE); |
|
521 } |
|
522 } |
|
523 } |
|
524 |
|
525 /** Computes the dependencies between directories |
|
526 */ |
|
527 void DirDef::computeDependencies() |
|
528 { |
|
529 FileList *fl = m_fileList; |
|
530 if (fl) |
|
531 { |
|
532 QListIterator<FileDef> fli(*fl); |
|
533 FileDef *fd; |
|
534 for (fli.toFirst();(fd=fli.current());++fli) // foreach file in dir dd |
|
535 { |
|
536 //printf(" File %s\n",fd->name().data()); |
|
537 //printf("** dir=%s file=%s\n",shortName().data(),fd->name().data()); |
|
538 QList<IncludeInfo> *ifl = fd->includeFileList(); |
|
539 if (ifl) |
|
540 { |
|
541 QListIterator<IncludeInfo> ifli(*ifl); |
|
542 IncludeInfo *ii; |
|
543 for (ifli.toFirst();(ii=ifli.current());++ifli) // foreach include file |
|
544 { |
|
545 //printf(" > %s\n",ii->includeName.data()); |
|
546 //printf(" #include %s\n",ii->includeName.data()); |
|
547 if (ii->fileDef && ii->fileDef->isLinkable()) // linkable file |
|
548 { |
|
549 DirDef *usedDir = ii->fileDef->getDirDef(); |
|
550 if (usedDir) |
|
551 { |
|
552 // add dependency: thisDir->usedDir |
|
553 //static int count=0; |
|
554 //printf(" %d: add dependency %s->%s\n",count++,name().data(),usedDir->name().data()); |
|
555 addUsesDependency(usedDir,fd,ii->fileDef,FALSE); |
|
556 } |
|
557 } |
|
558 } |
|
559 } |
|
560 } |
|
561 } |
|
562 } |
|
563 |
|
564 bool DirDef::isParentOf(DirDef *dir) const |
|
565 { |
|
566 if (dir->parent()==this) // this is a parent of dir |
|
567 return TRUE; |
|
568 else if (dir->parent()) // repeat for the parent of dir |
|
569 return isParentOf(dir->parent()); |
|
570 else |
|
571 return FALSE; |
|
572 } |
|
573 |
|
574 bool DirDef::depGraphIsTrivial() const |
|
575 { |
|
576 return FALSE; |
|
577 } |
|
578 |
|
579 //---------------------------------------------------------------------- |
|
580 |
|
581 int FilePairDict::compareItems(GCI item1,GCI item2) |
|
582 { |
|
583 FilePair *left = (FilePair*)item1; |
|
584 FilePair *right = (FilePair*)item2; |
|
585 int orderHi = stricmp(left->source()->name(),right->source()->name()); |
|
586 int orderLo = stricmp(left->destination()->name(),right->destination()->name()); |
|
587 return orderHi==0 ? orderLo : orderHi; |
|
588 } |
|
589 |
|
590 //---------------------------------------------------------------------- |
|
591 |
|
592 UsedDir::UsedDir(DirDef *dir,bool inherited) : |
|
593 m_dir(dir), m_filePairs(7), m_inherited(inherited) |
|
594 { |
|
595 m_filePairs.setAutoDelete(TRUE); |
|
596 } |
|
597 |
|
598 UsedDir::~UsedDir() |
|
599 { |
|
600 } |
|
601 |
|
602 |
|
603 void UsedDir::addFileDep(FileDef *srcFd,FileDef *dstFd) |
|
604 { |
|
605 m_filePairs.inSort(srcFd->getOutputFileBase()+dstFd->getOutputFileBase(), |
|
606 new FilePair(srcFd,dstFd)); |
|
607 } |
|
608 |
|
609 FilePair *UsedDir::findFilePair(const char *name) |
|
610 { |
|
611 QCString n=name; |
|
612 return n.isEmpty() ? 0 : m_filePairs.find(n); |
|
613 } |
|
614 |
|
615 DirDef *DirDef::createNewDir(const char *path) |
|
616 { |
|
617 ASSERT(path!=0); |
|
618 DirDef *dir = Doxygen::directories->find(path); |
|
619 if (dir==0) // new dir |
|
620 { |
|
621 //printf("Adding new dir %s\n",path); |
|
622 dir = new DirDef(path); |
|
623 //printf("createNewDir %s short=%s\n",path,dir->shortName().data()); |
|
624 Doxygen::directories->inSort(path,dir); |
|
625 } |
|
626 return dir; |
|
627 } |
|
628 |
|
629 bool DirDef::matchPath(const QCString &path,QStrList &l) |
|
630 { |
|
631 const char *s=l.first(); |
|
632 while (s) |
|
633 { |
|
634 QCString prefix = s; |
|
635 if (stricmp(prefix.left(path.length()),path)==0) // case insensitive compare |
|
636 { |
|
637 return TRUE; |
|
638 } |
|
639 s = l.next(); |
|
640 } |
|
641 return FALSE; |
|
642 } |
|
643 |
|
644 /*! strip part of \a path if it matches |
|
645 * one of the paths in the Config_getList("STRIP_FROM_PATH") list |
|
646 */ |
|
647 DirDef *DirDef::mergeDirectoryInTree(const QCString &path) |
|
648 { |
|
649 //printf("DirDef::mergeDirectoryInTree(%s)\n",path.data()); |
|
650 int p=0,i=0; |
|
651 DirDef *dir=0; |
|
652 while ((i=path.find('/',p))!=-1) |
|
653 { |
|
654 QCString part=path.left(i+1); |
|
655 if (!matchPath(part,Config_getList("STRIP_FROM_PATH")) && part!="/") |
|
656 { |
|
657 dir=createNewDir(part); |
|
658 } |
|
659 p=i+1; |
|
660 } |
|
661 return dir; |
|
662 } |
|
663 |
|
664 void DirDef::writeDepGraph(QTextStream &t) |
|
665 { |
|
666 writeDotDirDepGraph(t,this); |
|
667 } |
|
668 |
|
669 //---------------------------------------------------------------------- |
|
670 |
|
671 static void writePartialDirPath(OutputList &ol,const DirDef *root,const DirDef *target) |
|
672 { |
|
673 if (target->parent()!=root) |
|
674 { |
|
675 writePartialDirPath(ol,root,target->parent()); |
|
676 ol.writeString(" / "); |
|
677 } |
|
678 ol.writeObjectLink(target->getReference(),target->getOutputFileBase(),0,target->shortName()); |
|
679 } |
|
680 |
|
681 static void writePartialFilePath(OutputList &ol,const DirDef *root,const FileDef *fd) |
|
682 { |
|
683 if (fd->getDirDef() && fd->getDirDef()!=root) |
|
684 { |
|
685 writePartialDirPath(ol,root,fd->getDirDef()); |
|
686 ol.writeString(" / "); |
|
687 } |
|
688 if (fd->isLinkable()) |
|
689 { |
|
690 ol.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0,fd->name()); |
|
691 } |
|
692 else |
|
693 { |
|
694 ol.startBold(); |
|
695 ol.docify(fd->name()); |
|
696 ol.endBold(); |
|
697 } |
|
698 } |
|
699 |
|
700 void DirRelation::writeDocumentation(OutputList &ol) |
|
701 { |
|
702 ol.pushGeneratorState(); |
|
703 ol.disableAllBut(OutputGenerator::Html); |
|
704 |
|
705 QCString shortTitle=theTranslator->trDirRelation( |
|
706 m_src->shortName()+" → "+ |
|
707 m_dst->dir()->shortName()); |
|
708 QCString title=theTranslator->trDirRelation( |
|
709 m_src->displayName()+" -> "+ |
|
710 m_dst->dir()->shortName()); |
|
711 startFile(ol,getOutputFileBase(),getOutputFileBase(),title); |
|
712 |
|
713 // write navigation path |
|
714 m_src->writeNavigationPath(ol); |
|
715 |
|
716 //startTitle(ol,getOutputFileBase()); |
|
717 // ol.parseText(shortTitle); |
|
718 //endTitle(ol,getOutputFileBase(),title); |
|
719 ol.writeString("<h3>"+shortTitle+"</h3>"); |
|
720 |
|
721 ol.writeString("<table class=\"dirtab\">"); |
|
722 ol.writeString("<tr class=\"dirtab\">"); |
|
723 // TODO: translate me! "File in %s" |
|
724 ol.writeString("<th class=\"dirtab\">File in "); |
|
725 m_src->writePathFragment(ol); |
|
726 ol.writeString("</th>"); |
|
727 // TODO: translate me! "Includes file in %s" |
|
728 ol.writeString("<th class=\"dirtab\">Includes file in "); |
|
729 m_dst->dir()->writePathFragment(ol); |
|
730 ol.writeString("</th>"); |
|
731 ol.writeString("</tr>"); |
|
732 |
|
733 SDict<FilePair>::Iterator fpi(m_dst->filePairs()); |
|
734 FilePair *fp; |
|
735 for (fpi.toFirst();(fp=fpi.current());++fpi) |
|
736 { |
|
737 ol.writeString("<tr class=\"dirtab\">"); |
|
738 ol.writeString("<td class=\"dirtab\">"); |
|
739 writePartialFilePath(ol,m_src,fp->source()); |
|
740 ol.writeString("</td>"); |
|
741 ol.writeString("<td class=\"dirtab\">"); |
|
742 writePartialFilePath(ol,m_dst->dir(),fp->destination()); |
|
743 ol.writeString("</td>"); |
|
744 ol.writeString("</tr>"); |
|
745 } |
|
746 ol.writeString("</table>"); |
|
747 |
|
748 endFile(ol); |
|
749 ol.popGeneratorState(); |
|
750 } |
|
751 |
|
752 //---------------------------------------------------------------------- |
|
753 // external functions |
|
754 |
|
755 void buildDirectories() |
|
756 { |
|
757 // for each input file |
|
758 FileNameListIterator fnli(*Doxygen::inputNameList); |
|
759 FileName *fn; |
|
760 for (fnli.toFirst();(fn=fnli.current());++fnli) |
|
761 { |
|
762 FileNameIterator fni(*fn); |
|
763 FileDef *fd; |
|
764 for (;(fd=fni.current());++fni) |
|
765 { |
|
766 //printf("buildDirectories %s\n",fd->name().data()); |
|
767 if (fd->getReference().isEmpty() && !fd->isDocumentationFile()) |
|
768 { |
|
769 DirDef *dir; |
|
770 if ((dir=Doxygen::directories->find(fd->getPath()))==0) // new directory |
|
771 { |
|
772 dir = DirDef::mergeDirectoryInTree(fd->getPath()); |
|
773 } |
|
774 if (dir) dir->addFile(fd); |
|
775 } |
|
776 else |
|
777 { |
|
778 // do something for file imported via tag files. |
|
779 } |
|
780 } |
|
781 } |
|
782 |
|
783 //DirDef *root = new DirDef("root:"); |
|
784 // compute relations between directories => introduce container dirs. |
|
785 DirDef *dir; |
|
786 DirSDict::Iterator sdi(*Doxygen::directories); |
|
787 for (sdi.toFirst();(dir=sdi.current());++sdi) |
|
788 { |
|
789 //printf("New dir %s\n",dir->displayName().data()); |
|
790 QCString name = dir->name(); |
|
791 int i=name.findRev('/',name.length()-2); |
|
792 if (i>0) |
|
793 { |
|
794 DirDef *parent = Doxygen::directories->find(name.left(i+1)); |
|
795 //if (parent==0) parent=root; |
|
796 if (parent) |
|
797 { |
|
798 parent->addSubDir(dir); |
|
799 //printf("DirDef::addSubdir(): Adding subdir\n%s to\n%s\n", |
|
800 // dir->displayName().data(), parent->displayName().data()); |
|
801 } |
|
802 } |
|
803 } |
|
804 } |
|
805 |
|
806 void computeDirDependencies() |
|
807 { |
|
808 DirDef *dir; |
|
809 DirSDict::Iterator sdi(*Doxygen::directories); |
|
810 // compute nesting level for each directory |
|
811 for (sdi.toFirst();(dir=sdi.current());++sdi) |
|
812 { |
|
813 dir->setLevel(); |
|
814 } |
|
815 // compute uses dependencies between directories |
|
816 for (sdi.toFirst();(dir=sdi.current());++sdi) |
|
817 { |
|
818 //printf("computeDependencies for %s: #dirs=%d\n",dir->name().data(),Doxygen::directories.count()); |
|
819 dir->computeDependencies(); |
|
820 } |
|
821 |
|
822 #if 0 |
|
823 printf("-------------------------------------------------------------\n"); |
|
824 // print dependencies (for debugging) |
|
825 for (sdi.toFirst();(dir=sdi.current());++sdi) |
|
826 { |
|
827 if (dir->usedDirs()) |
|
828 { |
|
829 QDictIterator<UsedDir> udi(*dir->usedDirs()); |
|
830 UsedDir *usedDir; |
|
831 for (udi.toFirst();(usedDir=udi.current());++udi) |
|
832 { |
|
833 printf("%s depends on %s due to ", |
|
834 dir->shortName().data(),usedDir->dir()->shortName().data()); |
|
835 QDictIterator<FileDef> fdi(usedDir->files()); |
|
836 FileDef *fd; |
|
837 for (fdi.toFirst();(fd=fdi.current());++fdi) |
|
838 { |
|
839 printf("%s ",fd->name().data()); |
|
840 } |
|
841 printf("\n"); |
|
842 } |
|
843 } |
|
844 } |
|
845 printf("^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^\n"); |
|
846 #endif |
|
847 } |
|
848 |
|
849 #if 0 |
|
850 void writeDirDependencyGraph(const char *dirName) |
|
851 { |
|
852 QString path; |
|
853 DirDef *dir; |
|
854 DirSDict::Iterator sdi(*Doxygen::directories); |
|
855 QFile htmlPage(QCString(dirName)+"/dirdeps.html"); |
|
856 if (htmlPage.open(IO_WriteOnly)) |
|
857 { |
|
858 QTextStream out(&htmlPage); |
|
859 out << "<html><body>"; |
|
860 for (sdi.toFirst();(dir=sdi.current());++sdi) |
|
861 { |
|
862 path=dirName; |
|
863 path+="/"; |
|
864 path+=dir->getOutputFileBase(); |
|
865 path+="_dep.dot"; |
|
866 out << "<h4>" << dir->displayName() << "</h4>" << endl; |
|
867 out << "<img src=\"" << dir->getOutputFileBase() << "_dep.gif\">" << endl; |
|
868 QFile f(path); |
|
869 if (f.open(IO_WriteOnly)) |
|
870 { |
|
871 QTextStream t(&f); |
|
872 dir->writeDepGraph(t); |
|
873 } |
|
874 f.close(); |
|
875 |
|
876 QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT"); |
|
877 QCString outFile = QCString(dirName)+"/"+ |
|
878 dir->getOutputFileBase()+"_dep."+imgExt; |
|
879 DotRunner dotRun(path); |
|
880 dotRun.addJob(imgExt,outFile); |
|
881 dotRun.run(); |
|
882 |
|
883 //QCString dotArgs(4096); |
|
884 //dotArgs.sprintf("%s -Tgif -o %s",path.data(),outFile.data()); |
|
885 //if (portable_system(Config_getString("DOT_PATH")+"dot",dotArgs,FALSE)!=0) |
|
886 //{ |
|
887 // err("Problems running dot. Check your installation!\n"); |
|
888 //} |
|
889 } |
|
890 out << "</body></html>"; |
|
891 } |
|
892 htmlPage.close(); |
|
893 } |
|
894 #endif |
|
895 |
|
896 void generateDirDocs(OutputList &ol) |
|
897 { |
|
898 DirDef *dir; |
|
899 DirSDict::Iterator sdi(*Doxygen::directories); |
|
900 for (sdi.toFirst();(dir=sdi.current());++sdi) |
|
901 { |
|
902 dir->writeDocumentation(ol); |
|
903 } |
|
904 if (Config_getBool("DIRECTORY_GRAPH")) |
|
905 { |
|
906 SDict<DirRelation>::Iterator rdi(Doxygen::dirRelations); |
|
907 DirRelation *dr; |
|
908 for (rdi.toFirst();(dr=rdi.current());++rdi) |
|
909 { |
|
910 dr->writeDocumentation(ol); |
|
911 } |
|
912 } |
|
913 } |
|
914 |