00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <Basics.H>
00026 #include <FS.H>
00027 #include <CacheArgs.H>
00028 #include <CacheConfig.H>
00029 #include <SMultiPKFileRep.H>
00030 #include <PKPrefix.H>
00031 #include <BufStream.H>
00032
00033 using std::ostream;
00034 using std::ifstream;
00035 using std::ofstream;
00036 using std::cout;
00037 using std::cerr;
00038 using std::endl;
00039 using std::hex;
00040 using std::dec;
00041 using Basics::OBufStream;
00042
00043
00044
00045
00046 typedef Table<IntKey,FP::Tag>::Default CommonTagTbl;
00047
00048 static bool OpenFile(const Text fname, ifstream &ifs)
00049 throw (FS::Failure)
00050
00051
00052
00053
00054
00055 {
00056 try {
00057 FS::OpenReadOnly(fname, ifs);
00058 }
00059 catch (FS::DoesNotExist) {
00060 cerr << "Error: unable to open '" << fname << "' for reading." << endl;
00061 return false;
00062 }
00063 return true;
00064 }
00065
00066 static void Banner(ostream &os, char c, int num) throw ()
00067 {
00068 os << "// ";
00069 for (int i = 0; i < num; i++) os << c;
00070 os << endl;
00071 }
00072
00073 static void PrintFile(ostream &os, const char *nm, bool verbose)
00074 throw (SMultiPKFileRep::BadMPKFile, FS::EndOfFile, FS::Failure)
00075
00076
00077
00078
00079 {
00080
00081 Text fname(nm);
00082 if (nm[0] != '/') {
00083 fname = Config_SCachePath + '/' + fname;
00084 }
00085
00086
00087 ifstream ifs;
00088 if (!OpenFile(fname, ifs)) return;
00089
00090 try {
00091
00092 SMultiPKFileRep::Header hdr(ifs);
00093 hdr.ReadEntries(ifs);
00094 hdr.ReadPKFiles(ifs);
00095 FS::Close(ifs);
00096
00097
00098 Banner(os, '#', 74);
00099 os << "// <MultiPKFile> (" << fname << ")" << endl;
00100 Banner(os, '#', 74);
00101 hdr.Debug(os, verbose);
00102 for (int i = 0; i < hdr.num; i++) {
00103 SMultiPKFileRep::HeaderEntry *he;
00104 bool inTbl = hdr.pkTbl.Get(*(hdr.pkSeq[i]), he);
00105 assert(inTbl);
00106
00107
00108 if (he->pkfile != (SPKFile *)NULL) {
00109 he->pkfile->Debug(os, *(he->pkhdr), he->offset, verbose);
00110 }
00111 }
00112 os.flush();
00113 } catch (...) {
00114 FS::Close(ifs);
00115 throw;
00116 }
00117 }
00118
00119
00120
00121 Text HTMLQuote(const Text &original)
00122 {
00123 Text result;
00124 int origLen = original.Length(), doneCount = 0;
00125 while(doneCount < origLen)
00126 {
00127 int ltPos = original.FindChar('<', doneCount);
00128 int gtPos = original.FindChar('>', doneCount);
00129 int quotPos = original.FindChar('"', doneCount);
00130 int ampPos = original.FindChar('&', doneCount);
00131
00132
00133 if((ltPos >= 0) &&
00134 ((gtPos == -1) || (gtPos > ltPos)) &&
00135 ((quotPos == -1) || (quotPos > ltPos)) &&
00136 ((ampPos == -1) || (ampPos > ltPos)))
00137 {
00138
00139 result += original.Sub(doneCount, ltPos - doneCount);
00140
00141 result += "<";
00142
00143 doneCount = ltPos+1;
00144 }
00145
00146 else if((gtPos >= 0) &&
00147 ((ltPos == -1) || (ltPos > gtPos)) &&
00148 ((quotPos == -1) || (quotPos > gtPos)) &&
00149 ((ampPos == -1) || (ampPos > gtPos)))
00150 {
00151
00152 result += original.Sub(doneCount, gtPos - doneCount);
00153
00154 result += ">";
00155
00156 doneCount = gtPos+1;
00157 }
00158
00159 else if((quotPos >= 0) &&
00160 ((ltPos == -1) || (ltPos > quotPos)) &&
00161 ((gtPos == -1) || (gtPos > quotPos)) &&
00162 ((ampPos == -1) || (ampPos > quotPos)))
00163 {
00164
00165 result += original.Sub(doneCount, quotPos - doneCount);
00166
00167 result += """;
00168
00169 doneCount = quotPos+1;
00170 }
00171
00172 else if((ampPos >= 0) &&
00173 ((ltPos == -1) || (ltPos > ampPos)) &&
00174 ((gtPos == -1) || (gtPos > ampPos)) &&
00175 ((quotPos == -1) || (quotPos > ampPos)))
00176 {
00177
00178 result += original.Sub(doneCount, ampPos - doneCount);
00179
00180 result += "&";
00181
00182 doneCount = ampPos+1;
00183 }
00184
00185
00186 else
00187 {
00188 assert((ltPos == -1) && (gtPos == -1) &&
00189 (quotPos == -1) && (ampPos == -1));
00190 result += original.Sub(doneCount);
00191 doneCount = origLen;
00192 }
00193 }
00194 return result;
00195 }
00196
00197
00198 static Text Indent(unsigned int level)
00199 {
00200
00201
00202 static TextSeq l_IndentTexts;
00203
00204
00205 while(level >= l_IndentTexts.size())
00206 {
00207 unsigned int new_level = l_IndentTexts.size();
00208
00209 unsigned int new_len = new_level*2;
00210 char *indet_str = NEW_PTRFREE_ARRAY(char, new_len+1);
00211 unsigned int i = 0;
00212 while(i < new_len)
00213 {
00214 indet_str[i++] = ' ';
00215 }
00216 indet_str[new_len] = 0;
00217 l_IndentTexts.addhi(Text(indet_str, indet_str));
00218 }
00219
00220
00221 return l_IndentTexts.get(level);
00222 }
00223
00224 extern "C"
00225 {
00226
00227
00228 static int comparePaths(const void *a, const void *b)
00229 {
00230
00231 Text *ta = *((Text **) a), *tb = *((Text **) b);
00232
00233
00234
00235 bool a_dot = (((*ta)[2] == '.') && ((*ta)[3] == '/'));
00236 bool b_dot = (((*tb)[2] == '.') && ((*tb)[3] == '/'));
00237 if(a_dot && !b_dot)
00238 {
00239 return 1;
00240 }
00241 else if(b_dot && !a_dot)
00242 {
00243 return -1;
00244 }
00245
00246
00247 return strcmp(ta->cchars() + 2, tb->cchars() + 2);
00248 }
00249 }
00250
00251
00252 static void HTMLFVTable(ostream &os,
00253 unsigned int indent_level,
00254 const FV::List *names,
00255 const BitVector *nameSet,
00256 bool columnHeaders = true)
00257 {
00258
00259
00260 unsigned int nameTotal = nameSet->Cardinality(), nameCount = 0;
00261 Text **nameArray = NEW_ARRAY(Text *, nameTotal);
00262 BVIter namesIter(*nameSet);
00263 int nameIndex;
00264 while(namesIter.Next(nameIndex))
00265 {
00266 nameArray[nameCount++] = &(names->name[nameIndex]);
00267 }
00268 assert(nameCount == nameTotal);
00269
00270
00271 qsort(nameArray, nameTotal, sizeof(Text *), comparePaths);
00272
00273
00274 os << Indent(indent_level++) << "<table border>" << endl;
00275 if(columnHeaders)
00276 {
00277 os << Indent(indent_level++) << "<tr>" << endl
00278 << Indent(indent_level) << "<th>Type</th>" << endl
00279 << Indent(indent_level) << "<th>Path</th>" << endl
00280 << Indent(--indent_level) << "</tr>" << endl;
00281 }
00282 for(nameCount = 0; nameCount < nameTotal; nameCount++)
00283 {
00284 Text *name = nameArray[nameCount];
00285 char type = (*name)[0];
00286 Text quotedPath = HTMLQuote(name->Sub(2));
00287 os << Indent(indent_level++) << "<tr>" << endl
00288 << Indent(indent_level) << "<td><tt>" << HTMLQuote(type) << "</tt>";
00289
00290
00291 switch(type)
00292 {
00293 case 'N':
00294 os << " (value)";
00295 break;
00296 case '!':
00297 os << " (existence)";
00298 break;
00299 case 'T':
00300 os << " (type)";
00301 break;
00302 case 'L':
00303 os << " (list length)";
00304 break;
00305 case 'B':
00306 os << " (binding names)";
00307 break;
00308 case 'E':
00309 os << " (expression)";
00310 break;
00311 }
00312 os << "</td>" << endl
00313 << Indent(indent_level) << "<td><tt>" << quotedPath << "</tt></td>"
00314 << endl
00315 << Indent(--indent_level) << "</tr>" << endl;;
00316 }
00317 os << Indent(--indent_level) << "</table>" << endl;
00318 }
00319
00320
00321 static unsigned int StartHTML(ostream &os, const Text &title)
00322 {
00323 os << "<html>" << endl
00324 << " <head>" << endl
00325 << " <title>" << HTMLQuote(title) << "</title>" << endl
00326 << " </head>" << endl
00327 << " <body>" << endl;
00328
00329
00330 return 2;
00331 }
00332
00333
00334 static void EndHTML(ostream &os)
00335 {
00336 os << " </body>" << endl
00337 << "</html>" << endl;
00338 }
00339
00340 static Text ExpandURLPattern(const Text &pattern,
00341 PKPrefix::T pfx,
00342 FP::Tag *pk = 0,
00343 FV::Epoch *namesEpoch = 0,
00344 FP::Tag *cfp = 0,
00345 CacheEntry::Index *ci = 0)
00346 {
00347 Text result;
00348
00349
00350
00351 const char *pattern_kind = "MultiPKFile";
00352 if(ci != 0)
00353 {
00354 pattern_kind = "cache entry";
00355 }
00356 else if(cfp != 0)
00357 {
00358 pattern_kind = "common fingerprint group";
00359 }
00360 else if(pk != 0)
00361 {
00362 pattern_kind = "PKFile";
00363 }
00364
00365 int patternLen = pattern.Length(), doneCount = 0;
00366 bool
00367 pfx_included = false,
00368 pk_included = false,
00369 cfp_included = false,
00370 index_included = false;
00371 while(doneCount < patternLen)
00372 {
00373 int pctPos = pattern.FindChar('%', doneCount);
00374
00375 if(pctPos >= 0)
00376 {
00377
00378 result += pattern.Sub(doneCount, pctPos - doneCount);
00379
00380 switch (pattern[pctPos+1])
00381 {
00382 case 'm':
00383
00384 result += pfx.Pathname(PKPrefix::Granularity(),
00385 PKPrefix::Granularity());
00386 pfx_included = true;
00387 break;
00388 case 'p':
00389
00390 if(pk != 0)
00391 {
00392 OBufStream pk_str;
00393 pk->Print(pk_str, "_");
00394 result += pk_str.str();
00395 pk_included = true;
00396 }
00397 else
00398 {
00399 cerr << "Fatal error: %p ([p]rimary key) not valid in "
00400 << pattern_kind << " URL pattern." << endl
00401 << "\t" << pattern << endl;
00402 exit(2);
00403 }
00404 break;
00405 case 'n':
00406
00407 if(namesEpoch != 0)
00408 {
00409 OBufStream namesEpoch_str;
00410 namesEpoch_str << *namesEpoch;
00411 result += namesEpoch_str.str();
00412 index_included = true;
00413 }
00414 else
00415 {
00416 cerr << "Fatal error: %n ([n]amesEpoch) not valid in "
00417 << pattern_kind << " URL pattern." << endl
00418 << "\t" << pattern << endl;
00419 exit(2);
00420 }
00421 break;
00422 case 'c':
00423
00424 if(cfp != 0)
00425 {
00426 OBufStream cfp_str;
00427 cfp->Print(cfp_str, "_");
00428 result += cfp_str.str();
00429 cfp_included = true;
00430 }
00431 else
00432 {
00433 cerr << ("Fatal error: %c ([c]ommon fingerprint) not "
00434 "valid in ")
00435 << pattern_kind
00436 << " URL pattern." << endl
00437 << "\t" << pattern << endl;
00438 exit(2);
00439 }
00440 break;
00441 case 'i':
00442
00443 if(ci != 0)
00444 {
00445 OBufStream ci_str;
00446 ci_str << *ci;
00447 result += ci_str.str();
00448 index_included = true;
00449 }
00450 else
00451 {
00452 cerr << "Fatal error: %i (cache [i]ndex) not valid in "
00453 << pattern_kind
00454 << " URL pattern." << endl
00455 << "\t" << pattern << endl;
00456 exit(2);
00457 }
00458 break;
00459 case '%':
00460
00461 result += "%";
00462 break;
00463 defrault:
00464
00465
00466 result += pattern.Sub(pctPos, 2);
00467 break;
00468 }
00469
00470
00471 doneCount = pctPos+2;
00472 }
00473
00474
00475 else
00476 {
00477 result += pattern.Sub(doneCount);
00478 doneCount = patternLen;
00479 }
00480 }
00481
00482
00483
00484 if(ci != 0)
00485 {
00486
00487 if(!pk_included && !pfx_included)
00488 {
00489 cerr << "Fatal error: " << pattern_kind
00490 << (" URL pattern contains neither %p ([p]rimary key) "
00491 "nor %m (PK prefix identifying [M]ultiPKFile)!")
00492 << endl
00493 << "\t" << pattern << endl;
00494 exit(2);
00495 }
00496
00497 if(!index_included)
00498 {
00499 cerr << "Fatal error: " << pattern_kind
00500 << " URL pattern doesn't contain %i (cache [i]ndex)!"
00501 << endl
00502 << "\t" << pattern << endl;
00503 exit(2);
00504 }
00505 }
00506 else if(cfp != 0)
00507 {
00508
00509 if(!pk_included)
00510 {
00511 cerr << "Fatal error: " << pattern_kind
00512 << " URL pattern doesn't contain %p ([p]rimary key)!" << endl
00513 << "\t" << pattern << endl;
00514 exit(2);
00515 }
00516
00517 if(!cfp_included)
00518 {
00519 cerr << "Fatal error: " << pattern_kind
00520 << " URL pattern doesn't contain %c ([c]ommon fingerprint)!"
00521 << endl
00522 << "\t" << pattern << endl;
00523 exit(2);
00524 }
00525 }
00526 else if(pk != 0)
00527 {
00528
00529 if(!pk_included)
00530 {
00531 cerr << "Fatal error: " << pattern_kind
00532 << " URL pattern doesn't contain %p ([p]rimary key)!" << endl
00533 << "\t" << pattern << endl;
00534 exit(2);
00535 }
00536 }
00537 else
00538 {
00539
00540 if(!pfx_included)
00541 {
00542 cerr << "Fatal error: " << pattern_kind
00543 << (" URL pattern doesn't contain "
00544 "%m (PK prefix identifying [M]ultiPKFile)!") << endl
00545 << "\t" << pattern << endl;
00546 exit(2);
00547 }
00548 }
00549
00550 return result;
00551 }
00552
00553
00554 static Text MPKFileHTMLFileName(PKPrefix::T pfx)
00555 {
00556 OBufStream l_name;
00557 l_name << "mpkfile_"
00558 << pfx.Pathname(PKPrefix::Granularity(), PKPrefix::Granularity())
00559 << ".html";
00560 return Text(l_name.str());
00561 }
00562
00563 static Text g_MPKFileURL_pattern;
00564 static bool g_MPKFileURL_pattern_set = false;
00565
00566 static Text MPKFileURL(PKPrefix::T pfx)
00567 {
00568 if(!g_MPKFileURL_pattern_set)
00569 {
00570 return MPKFileHTMLFileName(pfx);
00571 }
00572
00573 return ExpandURLPattern(g_MPKFileURL_pattern, pfx);
00574 }
00575
00576
00577 static Text PKFileHTMLFileName(FP::Tag pk)
00578 {
00579 OBufStream l_name;
00580 l_name << "pkfile_";
00581 pk.Print(l_name, "_");
00582 l_name << ".html";
00583 return Text(l_name.str());
00584 }
00585
00586 static Text g_PKFileURL_pattern;
00587 static bool g_PKFileURL_pattern_set = false;
00588
00589 static Text PKFileURL(FP::Tag pk)
00590 {
00591 if(!g_PKFileURL_pattern_set)
00592 {
00593 return PKFileHTMLFileName(pk);
00594 }
00595
00596 return ExpandURLPattern(g_PKFileURL_pattern, PKPrefix::T(pk), &pk);
00597 }
00598
00599
00600 static Text CFPGroupHTMLFileName(FP::Tag pk, FP::Tag cfp)
00601 {
00602 OBufStream l_name;
00603 l_name << "pkfile_";
00604 pk.Print(l_name, "_");
00605 l_name << "_cfp_";
00606 cfp.Print(l_name, "_");
00607 l_name << ".html";
00608 return Text(l_name.str());
00609 }
00610
00611 static Text g_CFPGroupURL_pattern;
00612 static bool g_CFPGroupURL_pattern_set = false;
00613
00614 static Text CFPGroupURL(FP::Tag pk, FV::Epoch namesEpoch, FP::Tag cfp)
00615 {
00616 if(!g_CFPGroupURL_pattern_set)
00617 {
00618 return CFPGroupHTMLFileName(pk, cfp);
00619 }
00620
00621 return ExpandURLPattern(g_CFPGroupURL_pattern,
00622 PKPrefix::T(pk), &pk,
00623 &namesEpoch, &cfp);
00624 }
00625
00626
00627 static Text CacheEntryHTMLFileName(CacheEntry::Index ci)
00628 {
00629 OBufStream l_name;
00630 l_name << "ci_" << ci << ".html";
00631 return Text(l_name.str());
00632 }
00633
00634 static Text g_CacheEntryURL_pattern;
00635 static bool g_CacheEntryURL_pattern_set = false;
00636
00637 static Text CacheEntryURL(FP::Tag pk, CacheEntry::Index ci)
00638 {
00639 if(!g_CacheEntryURL_pattern_set)
00640 {
00641 return CacheEntryHTMLFileName(ci);
00642 }
00643
00644 return ExpandURLPattern(g_CacheEntryURL_pattern,
00645 PKPrefix::T(pk), &pk,
00646
00647 0, 0,
00648 &ci);
00649 }
00650
00651
00652
00653 static Text CombinePath(const Text &dir, const Text &tail)
00654 {
00655 OBufStream l_result;
00656 l_result << dir;
00657 if(dir[dir.Length() - 1] != PathnameSep)
00658 {
00659 l_result << PathnameSep;
00660 }
00661 l_result << tail;
00662 return Text(l_result.str());
00663 }
00664
00665
00666
00667
00668 struct HTMLFileInfo
00669 {
00670
00671 Text title;
00672
00673
00674 Text fname;
00675
00676
00677 Text url;
00678
00679
00680 ofstream out;
00681
00682
00683 unsigned int indent_level;
00684
00685
00686 inline Text indent()
00687 {
00688 return Indent(this->indent_level);
00689 }
00690
00691 inline Text indentOpen()
00692 {
00693 return Indent((this->indent_level)++);
00694 }
00695
00696
00697 inline Text indentClose()
00698 {
00699 return Indent(--(this->indent_level));
00700 }
00701 };
00702
00703
00704 static void PrintCacheEntryHTML(const Text &out_dir, bool print_fnames,
00705
00706 HTMLFileInfo &mpk_html,
00707
00708 HTMLFileInfo &pkfile_html,
00709
00710 HTMLFileInfo &cfp_html,
00711
00712 SMultiPKFileRep::HeaderEntry *he,
00713
00714 CE::T *entry,
00715
00716
00717
00718 BitVector &uncommonCommon,
00719 bool uncommonCommon_empty)
00720 throw (FS::EndOfFile, FS::Failure)
00721 {
00722 HTMLFileInfo ce_html;
00723
00724
00725 ce_html.fname = CacheEntryHTMLFileName(entry->CI());
00726 FS::OpenForWriting(CombinePath(out_dir, ce_html.fname), ce_html.out);
00727 if(print_fnames)
00728 cout << "Writing " << ce_html.fname << endl;
00729
00730
00731 ce_html.url = CacheEntryURL(he->pk, entry->CI());
00732
00733
00734 {
00735 OBufStream l_title;
00736 l_title << "Cache entry, index = " << entry->CI();
00737 ce_html.title = l_title.str();
00738 }
00739
00740
00741 ce_html.indent_level = StartHTML(ce_html.out, ce_html.title);
00742
00743
00744
00745 mpk_html.out
00746 << mpk_html.indent()
00747 << "<li><a href=\"" << ce_html.url << "\">" << ce_html.title
00748 << "</a></li>" << endl;
00749 pkfile_html.out
00750 << pkfile_html.indent()
00751 << "<li><a href=\"" << ce_html.url << "\">" << ce_html.title
00752 << "</a></li>" << endl;
00753 cfp_html.out
00754 << cfp_html.indent()
00755 << "<li><a href=\"" << ce_html.url << "\">" << ce_html.title
00756 << "</a></li>" << endl;
00757
00758 ce_html.out
00759
00760 << ce_html.indent() << "Up: <a href=\"" << mpk_html.url
00761 << "\">" << mpk_html.title << "</a><br>" << endl
00762 << ce_html.indent() << "Up: <a href=\"" << pkfile_html.url
00763 << "\">" << pkfile_html.title << "</a><br>" << endl
00764 << ce_html.indent() << "Up: <a href=\"" << cfp_html.url
00765 << "\">" << cfp_html.title << "</a><br>" << endl
00766 << ce_html.indent() << "<hr>" << endl
00767
00768 << ce_html.indent() << "<h1>" << ce_html.title << "</h1>" << endl;
00769
00770
00771
00772 if(uncommonCommon_empty)
00773 {
00774 if(entry->UncommonNames()->IsEmpty())
00775 {
00776 ce_html.out
00777 << ce_html.indent() << "<p>No uncommon secondary dependencies.</p>"
00778 << endl;
00779 }
00780 else
00781 {
00782 ce_html.out
00783 << ce_html.indent() << "<p>Uncommon secondary dependencies ("
00784 << entry->UncommonNames()->Cardinality()
00785 << " total):</p>"
00786 << endl;
00787 HTMLFVTable(ce_html.out, ce_html.indent_level,
00788 he->pkfile->AllNames(), entry->UncommonNames());
00789 }
00790 }
00791 else
00792 {
00793
00794
00795 BitVector uncommonUnique(entry->UncommonNames());
00796 uncommonUnique -= uncommonCommon;
00797
00798 if(uncommonUnique.IsEmpty())
00799 {
00800 ce_html.out
00801 << ce_html.indent()
00802 << "<p>There are no uncommon secondary "
00803 << "dependencies used by this entry but not "
00804 << "others in its CFP group.</p>" << endl;
00805 }
00806 else
00807 {
00808 ce_html.out
00809 << ce_html.indent()
00810 << "<p>Uncommon secondary dependencies used "
00811 << "by this entry but not others in its CFP "
00812 << "group ("
00813 << uncommonUnique.Cardinality()
00814 << " total):</p>" << endl;
00815 HTMLFVTable(ce_html.out, ce_html.indent_level,
00816 he->pkfile->AllNames(), &uncommonUnique);
00817 }
00818 }
00819
00820
00821 if(entry->Kids()->len == 0)
00822 {
00823 ce_html.out
00824 << ce_html.indent() << "<p>No child cache entries.</p>" << endl;
00825 }
00826 else
00827 {
00828 ce_html.out
00829 << ce_html.indent() << "<p>Child cache entries ("
00830 << entry->Kids()->len
00831 << " total):</p>" << endl
00832 << ce_html.indentOpen()
00833 << "<ul>" << endl;
00834 for(int kid_i = 0; kid_i < entry->Kids()->len; kid_i++)
00835 {
00836 CacheEntry::Index kid = entry->Kids()->index[kid_i];
00837 ce_html.out
00838 << ce_html.indent()
00839 << "<li>" << kid << "</li>" << endl;
00840 }
00841 ce_html.out << ce_html.indentClose() << "</ul>" << endl;
00842 }
00843
00844
00845 const VestaVal::T *value = entry->Value();
00846 if(value->dis.len == 0)
00847 {
00848 ce_html.out
00849 << ce_html.indent() << "<p>No result files.</p>" << endl;
00850 }
00851 else
00852 {
00853 ce_html.out
00854 << ce_html.indent() << "<p>Result files (" << value->dis.len
00855 << " total):</p>" << endl
00856 << ce_html.indentOpen() << "<ul>" << endl << hex;
00857 for(int di_i = 0; di_i < value->dis.len; di_i++)
00858 {
00859 ce_html.out
00860 << ce_html.indent() << "<li>";
00861 ShortId di = value->dis.index[di_i];
00862 bool anchored = false;
00863 if(!SourceOrDerived::dirShortId(di))
00864 {
00865 char *di_path =
00866 SourceOrDerived::shortIdToName(di, false);
00867 ce_html.out << "<a href=\"file://" << di_path
00868 << "\">";
00869 anchored = true;
00870 }
00871 ce_html.out << "0x" << di;
00872 if(anchored)
00873 {
00874 ce_html.out << "</a>";
00875 }
00876 ce_html.out << "</li>" << endl;
00877 }
00878 ce_html.out << dec << ce_html.indentClose() << "</ul>" << endl;
00879 }
00880
00881
00882 ce_html.out
00883 << ce_html.indent() << "<p>Stored value size: " << value->len
00884 << " bytes.</p>" << endl;
00885
00886
00887 ce_html.out
00888 << ce_html.indent() << "<p>Value PrefixTbl size: "
00889 << value->prefixTbl.NumArcs() << " entries.";
00890
00891
00892
00893 if(value->prefixTbl.NumArcs() > (PrefixTbl::endMarker / 2))
00894 {
00895 ce_html.out
00896 << ce_html.indent() << " (Note: the maximum possible size is "
00897 << PrefixTbl::endMarker
00898 << (" entries. The size of the PrefixTbl is "
00899 "affected by the size of the entry's result value and the "
00900 "number of distinct dependency paths recorded in the "
00901 "entry's result value.)");
00902 }
00903 ce_html.out << "</p>" << endl;
00904
00905
00906 EndHTML(ce_html.out);
00907 ce_html.out.flush();
00908 ce_html.out.close();
00909 }
00910
00911
00912
00913
00914 static void PrintCFPGroupHTML(const Text &out_dir, bool print_fnames,
00915
00916 HTMLFileInfo &mpk_html,
00917
00918 HTMLFileInfo &pkfile_html,
00919
00920 SMultiPKFileRep::HeaderEntry *he,
00921
00922 unsigned int cfp_index,
00923
00924
00925 CommonTagTbl *commonTags)
00926 throw (FS::EndOfFile, FS::Failure)
00927 {
00928 HTMLFileInfo cfp_html;
00929
00930 FP::Tag cfp = he->pkhdr->entry[cfp_index].cfp;
00931
00932
00933 cfp_html.fname = CFPGroupHTMLFileName(he->pk, cfp);
00934 FS::OpenForWriting(CombinePath(out_dir, cfp_html.fname), cfp_html.out);
00935 if(print_fnames)
00936 cout << "Writing " << cfp_html.fname << endl;
00937
00938
00939 cfp_html.url = CFPGroupURL(he->pk, he->pkfile->NamesEpoch(), cfp);
00940
00941
00942 {
00943 OBufStream l_title;
00944 l_title << "Common fingerprint Group " << cfp_index << ": " << cfp;
00945 cfp_html.title = l_title.str();
00946 }
00947
00948
00949 cfp_html.indent_level = StartHTML(cfp_html.out, cfp_html.title);
00950
00951
00952
00953 mpk_html.out
00954 << mpk_html.indent()
00955 << "<li><a href=\"" << cfp_html.url << "\">" << cfp_html.title
00956 << "</a></li>" << endl;
00957 pkfile_html.out
00958 << pkfile_html.indent()
00959 << "<li><a href=\"" << cfp_html.url << "\">" << cfp_html.title
00960 << "</a></li>" << endl;
00961
00962 cfp_html.out
00963
00964 << cfp_html.indent() << "Up: <a href=\"" << mpk_html.url
00965 << "\">" << mpk_html.title << "</a><br>" << endl
00966
00967 << cfp_html.indent() << "Up: <a href=\"" << pkfile_html.url
00968 << "\">" << pkfile_html.title << "</a><br>" << endl
00969 << cfp_html.indent() << "<hr>" << endl
00970
00971 << cfp_html.indent() << "<h1>" << cfp_html.title << "</h1>" << endl;
00972
00973
00974
00975 if(he->pkhdr->num > 1)
00976 {
00977 cfp_html.out
00978 << cfp_html.indent()
00979 << "<p>Common secondary dependencies with different "
00980 << "fingerprints (values) in other CFP groups:</p>" << endl
00981 << cfp_html.indentOpen() << "<table border>" << endl
00982 << cfp_html.indentOpen() << "<tr>" << endl
00983 << cfp_html.indent() << "<th>CFP Group</th>" << endl
00984 << cfp_html.indent() << "<th>Differing dependencies</th>" << endl
00985 << cfp_html.indentClose() << "</tr>" << endl;
00986
00987
00988
00989
00990 for(int cfp_j = 0; cfp_j < he->pkhdr->num; cfp_j++)
00991 {
00992 if(cfp_index == cfp_j)
00993 continue;
00994 cfp_html.out
00995 << cfp_html.indentOpen() << "<tr>" << endl
00996 << cfp_html.indentOpen() << "<td>" << endl
00997 << cfp_html.indent() << cfp_j << "<br>" << endl
00998 << cfp_html.indent() << he->pkhdr->entry[cfp_j].cfp << endl
00999 << cfp_html.indentClose() << "</td>" << endl
01000 << cfp_html.indentOpen() << "<td>" << endl;
01001
01002
01003
01004 BitVector commonDiff;
01005 BVIter commonIter(*(he->pkfile->CommonNames()));
01006 int commonIndex;
01007 while(commonIter.Next(commonIndex))
01008 {
01009
01010
01011 FP::Tag myFP, theirFP;
01012 bool inTbl = commonTags[cfp_index].Get(commonIndex,
01013 myFP);
01014 assert(inTbl);
01015 inTbl = commonTags[cfp_j].Get(commonIndex,
01016 theirFP);
01017 assert(inTbl);
01018
01019
01020 if(myFP != theirFP)
01021 {
01022 commonDiff.Set(commonIndex);
01023 }
01024 }
01025
01026
01027 cfp_html.out
01028 << cfp_html.indent() << commonDiff.Cardinality()
01029 << " total:" << endl;
01030 HTMLFVTable(cfp_html.out, cfp_html.indent_level,
01031 he->pkfile->AllNames(), &commonDiff);
01032
01033
01034 cfp_html.out << cfp_html.indentClose() << "</td>" << endl
01035 << cfp_html.indentClose() << "</tr>" << endl;
01036 }
01037
01038 cfp_html.out << cfp_html.indentClose() << "</table>" << endl;
01039
01040 }
01041
01042
01043 CE::List *list;
01044 bool inTbl = he->pkfile->OldEntries()->Get(cfp, list);
01045 assert(inTbl);
01046 unsigned int entry_count = 1;
01047
01048
01049
01050 BitVector uncommonCommon;
01051 bool uncommonCommon_empty = true;
01052
01053
01054 if(list->Tail() != 0)
01055 {
01056
01057 CE::List *temp_list = list;
01058 while(temp_list != 0)
01059 {
01060 CE::T *entry = temp_list->Head();
01061 assert(entry != 0);
01062
01063
01064
01065 if(uncommonCommon_empty)
01066 {
01067 uncommonCommon = *(entry->UncommonNames());
01068 uncommonCommon_empty = false;
01069 }
01070 else
01071 {
01072 uncommonCommon &= *(entry->UncommonNames());
01073 }
01074
01075 temp_list = temp_list->Tail();
01076
01077
01078 entry_count++;
01079 }
01080
01081
01082
01083 unsigned int uncommonCommon_count = uncommonCommon.Cardinality();
01084 if(uncommonCommon_count > 0)
01085 {
01086 cfp_html.out
01087 << cfp_html.indent()
01088 << "<p>Uncommon secondary dependencies used by all "
01089 << "entries in this CFP group (" << uncommonCommon_count
01090 << " total):</p>" << endl;
01091 HTMLFVTable(cfp_html.out, cfp_html.indent_level,
01092 he->pkfile->AllNames(), &uncommonCommon);
01093 }
01094 else
01095 {
01096 cfp_html.out
01097 << cfp_html.indent()
01098 << "<p>There are no uncommon secondary dependencies common to all "
01099 << "entries in this CFP group:</p>" << endl;
01100 uncommonCommon_empty = true;
01101 }
01102 }
01103
01104
01105
01106 cfp_html.out
01107 << cfp_html.indent() << "<p>Cache entries (" << entry_count
01108 << " total):</p>" << endl
01109 << cfp_html.indentOpen() << "<ul>" << endl;
01110 pkfile_html.out
01111 << pkfile_html.indent() << "Cache entries (" << entry_count
01112 << " total):" << endl
01113 << pkfile_html.indentOpen() << "<ul>" << endl;
01114 mpk_html.out
01115 << mpk_html.indent() << "Cache entries (" << entry_count
01116 << " total):" << endl
01117 << mpk_html.indentOpen() << "<ul>" << endl;
01118
01119
01120 while(list != 0)
01121 {
01122 CE::T *entry = list->Head();
01123 assert(entry != 0);
01124
01125 PrintCacheEntryHTML(out_dir, print_fnames,
01126 mpk_html, pkfile_html, cfp_html,
01127 he, entry, uncommonCommon, uncommonCommon_empty);
01128
01129 list = list->Tail();
01130 }
01131
01132
01133 cfp_html.out << cfp_html.indentClose() << "</ul>" << endl;
01134 pkfile_html.out << pkfile_html.indentClose() << "</ul>" << endl;
01135 mpk_html.out << mpk_html.indentClose() << "</ul>" << endl;
01136
01137
01138 EndHTML(cfp_html.out);
01139 cfp_html.out.flush();
01140 cfp_html.out.close();
01141 }
01142
01143
01144
01145
01146 static void PrintPKFileHTML(const Text &out_dir, bool print_fnames,
01147
01148 HTMLFileInfo &mpk_html,
01149
01150 unsigned int pkfile_index,
01151
01152 SMultiPKFileRep::HeaderEntry *he)
01153 throw (FS::EndOfFile, FS::Failure)
01154 {
01155 HTMLFileInfo pkfile_html;
01156
01157
01158 pkfile_html.fname = PKFileHTMLFileName(he->pk);
01159 FS::OpenForWriting(CombinePath(out_dir, pkfile_html.fname), pkfile_html.out);
01160 if(print_fnames)
01161 cout << "Writing " << pkfile_html.fname << endl;
01162
01163
01164 pkfile_html.url = PKFileURL(he->pk);
01165
01166
01167 {
01168 OBufStream l_title;
01169 l_title << "PKFile " << pkfile_index << ": " << he->pk;
01170 pkfile_html.title = l_title.str();
01171 }
01172
01173
01174 pkfile_html.indent_level = StartHTML(pkfile_html.out, pkfile_html.title);
01175
01176
01177
01178 Text sourceFunc = ((he->pkfile->SourceFunc() == 0)
01179 ? Text("<i>UNKNOWN</i>")
01180 : (Text("<tt>")+
01181 HTMLQuote(*(he->pkfile->SourceFunc()))+
01182 "</tt>"));
01183
01184
01185 mpk_html.out
01186 << mpk_html.indent()
01187 << "<li><a href=\"" << pkfile_html.url << "\">" << pkfile_html.title
01188 << "</a><br>" << endl;
01189 mpk_html.out
01190 << mpk_html.indent() << "Function: " << sourceFunc << "</li>" << endl;
01191
01192 pkfile_html.out
01193
01194 << pkfile_html.indent() << "Up: <a href=\"" << mpk_html.url
01195 << "\">" << mpk_html.title << "</a>" << endl
01196 << pkfile_html.indent() << "<hr>" << endl
01197
01198 << pkfile_html.indent() << "<h1>" << pkfile_html.title << "</h1>" << endl
01199
01200 << pkfile_html.indent() << "<p>Function:</p>" << endl
01201 << pkfile_html.indent() << "<blockquote>" << sourceFunc
01202 << "</blockquote>" << endl
01203
01204 << pkfile_html.indent()
01205 << "<p>PKFile epoch (incremented each time the PKFile is re-written): "
01206 << he->pkfile->PKEpoch() << "</p>" << endl
01207 << pkfile_html.indent()
01208 << ("<p>Secondary dependency names epoch (incremented each time "
01209 "secondary dependencies are added or deleted): ")
01210 << he->pkfile->NamesEpoch() << "</p>" << endl
01211
01212 << pkfile_html.indent() << "<p>Common secondary dependencies ("
01213 << he->pkfile->CommonNames()->Cardinality()
01214 << " total):</p>" << endl;
01215 HTMLFVTable(pkfile_html.out, pkfile_html.indent_level,
01216 he->pkfile->AllNames(), he->pkfile->CommonNames());
01217
01218
01219
01220
01221 CommonTagTbl *commonTags = NEW_ARRAY(CommonTagTbl, he->pkhdr->num);
01222 for(int cfp_i = 0; cfp_i < he->pkhdr->num; cfp_i++)
01223 {
01224
01225 CE::List *list;
01226 bool inTbl =
01227 he->pkfile->OldEntries()->Get(he->pkhdr->entry[cfp_i].cfp,
01228 list);
01229 assert(inTbl);
01230 assert(list != 0);
01231 CE::T *entry = list->Head();
01232 assert(entry != 0);
01233
01234
01235 BVIter commonIter(*(he->pkfile->CommonNames()));
01236 int commonIndex;
01237 while(commonIter.Next(commonIndex))
01238 {
01239
01240 int fpsIndex = commonIndex;
01241 if(entry->IMap() != 0)
01242 {
01243 short temp;
01244 inTbl = entry->IMap()->Get(commonIndex, temp);
01245 assert(inTbl);
01246 fpsIndex = temp;
01247 }
01248
01249
01250 inTbl = commonTags[cfp_i].Put(commonIndex,
01251 entry->FPs()->fp[fpsIndex]);
01252 assert(!inTbl);
01253 }
01254 }
01255
01256
01257
01258 pkfile_html.out
01259 << pkfile_html.indent() << "<p>Common fingerprint groups ("
01260 << he->pkhdr->num << " total):</p>" << endl
01261 << pkfile_html.indentOpen() << "<ul>" << endl;
01262 mpk_html.out
01263 << mpk_html.indent() << "Common fingerprint groups ("
01264 << he->pkhdr->num << " total):" << endl
01265 << mpk_html.indentOpen() << "<ul>" << endl;
01266
01267
01268 for(int cfp_i = 0; cfp_i < he->pkhdr->num; cfp_i++)
01269 {
01270
01271 PrintCFPGroupHTML(out_dir, print_fnames,
01272 mpk_html, pkfile_html,
01273 he, cfp_i, commonTags);
01274 }
01275
01276
01277 pkfile_html.out << pkfile_html.indentClose() << "</ul>" << endl;
01278 mpk_html.out << mpk_html.indentClose() << "</ul>" << endl;
01279
01280
01281 EndHTML(pkfile_html.out);
01282 FS::Close(pkfile_html.out);
01283 }
01284
01285
01286
01287
01288 static void PrintFileHTML(const Text &out_dir, bool print_fnames,
01289 const char *nm)
01290 throw (SMultiPKFileRep::BadMPKFile, FS::EndOfFile, FS::Failure)
01291 {
01292
01293 Text fname(nm);
01294 if (nm[0] != '/') {
01295 fname = Config_SCachePath + '/' + fname;
01296 }
01297
01298
01299 ifstream ifs;
01300 if (!OpenFile(fname, ifs)) return;
01301
01302 try {
01303
01304 SMultiPKFileRep::Header hdr(ifs);
01305 hdr.ReadEntries(ifs);
01306 hdr.ReadPKFiles(ifs);
01307 FS::Close(ifs);
01308
01309 HTMLFileInfo mpk_html;
01310
01311
01312 assert(hdr.num > 0);
01313 PKPrefix::T pfx(*(hdr.pkSeq[0]));
01314 mpk_html.fname = MPKFileHTMLFileName(pfx);
01315 FS::OpenForWriting(CombinePath(out_dir, mpk_html.fname), mpk_html.out);
01316 if(print_fnames)
01317 cout << "Writing " << mpk_html.fname << endl;
01318
01319
01320 mpk_html.url = MPKFileURL(pfx);
01321
01322
01323 {
01324 OBufStream l_title;
01325 l_title << "MultiPKFile " << HTMLQuote(fname);
01326 mpk_html.title = l_title.str();
01327 }
01328
01329
01330 mpk_html.indent_level = StartHTML(mpk_html.out, mpk_html.title);
01331
01332 mpk_html.out
01333
01334 << mpk_html.indent() << "<h1>" << mpk_html.title << "</h1>" << endl
01335 << mpk_html.indent() << "<p>PKFiles (" << hdr.num
01336 << " total):</p>" << endl
01337 << mpk_html.indentOpen() << "<ul>" << endl;
01338
01339
01340 for (int i = 0; i < hdr.num; i++) {
01341 SMultiPKFileRep::HeaderEntry *he;
01342 bool inTbl = hdr.pkTbl.Get(*(hdr.pkSeq[i]), he);
01343 assert(inTbl);
01344
01345
01346
01347 PrintPKFileHTML(out_dir, print_fnames, mpk_html, i, he);
01348 }
01349
01350
01351 mpk_html.out
01352 << mpk_html.indentClose() << "</ul>" << endl;
01353
01354
01355 EndHTML(mpk_html.out);
01356 FS::Close(mpk_html.out);
01357 } catch (...) {
01358 FS::Close(ifs);
01359 throw;
01360 }
01361 }
01362
01363 static void ExitProgram(char *msg) throw ()
01364 {
01365 cerr << "Fatal error: " << msg << endl;
01366 cerr << "Syntax: PrintMPKFile" << endl
01367 << " [-verbose]" << endl
01368 << " [-html [directory]]" << endl
01369 << " [-url-patterns mpkfile pkfile cfp-group entry]" << endl
01370 << " file ..." << endl;
01371 exit(1);
01372 }
01373
01374 int main(int argc, char *argv[])
01375 {
01376 bool verbose = false;
01377 bool html = false;
01378 const char *html_dir = ".";
01379
01380
01381 int arg = 1;
01382 for (; arg < argc && *argv[arg] == '-'; arg++) {
01383 if (CacheArgs::StartsWith(argv[arg], "-verbose")) {
01384 verbose = true;
01385 } else if (CacheArgs::StartsWith(argv[arg], "-html")) {
01386 html = true;
01387 arg++;
01388 if((arg < argc) && FS::IsDirectory(argv[arg]))
01389 {
01390 html_dir = argv[arg];
01391 }
01392 else
01393 {
01394 arg--;
01395 }
01396 } else if (CacheArgs::StartsWith(argv[arg], "-url-patterns")) {
01397 if((arg + 4) > argc)
01398 {
01399 ExitProgram("-url-patterns needs 4 pattern arguments: "
01400 "MultiPKFile, PKFile, common fingerprint group, "
01401 "cache entry");
01402 }
01403 g_MPKFileURL_pattern = argv[++arg];
01404 g_MPKFileURL_pattern_set = true;
01405 g_PKFileURL_pattern = argv[++arg];
01406 g_PKFileURL_pattern_set = true;
01407 g_CFPGroupURL_pattern = argv[++arg];
01408 g_CFPGroupURL_pattern_set = true;
01409 g_CacheEntryURL_pattern = argv[++arg];
01410 g_CacheEntryURL_pattern_set = true;
01411 } else{
01412 ExitProgram("unrecognized command-line option");
01413 }
01414 }
01415
01416
01417 if (argc - arg < 1) {
01418 ExitProgram("no file arguments specified");
01419 }
01420 bool firstFile = true;
01421 for (; arg < argc; arg++) {
01422 try {
01423 if (firstFile) firstFile = false; else cout << endl;
01424 if(html)
01425 {
01426 PrintFileHTML(html_dir, verbose, argv[arg]);
01427 }
01428 else
01429 {
01430 PrintFile(cout, argv[arg], verbose);
01431 }
01432 }
01433 catch (SMultiPKFileRep::BadMPKFile) {
01434 cerr << "Error: '" << argv[arg]
01435 << "' is a bad MultiPKFile" << endl;
01436 }
01437 catch (FS::EndOfFile) {
01438 cerr << "Fatal error: unexpected end-of-file" << endl;
01439 }
01440 catch (const FS::Failure &f) {
01441 cerr << f;
01442 }
01443 }
01444 return 0;
01445 }