Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

PrintMPKFile.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // Last modified on Thu Apr 28 23:28:54 EDT 2005 by ken@xorian.net  
00020 //      modified on Sat Feb 12 13:11:57 PST 2000 by mann  
00021 //      modified on Sun Aug 23 11:38:57 PDT 1998 by heydon
00022 
00023 // PrintMPKFile -- print the contents of a MultiPKFile
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 // This table type is used to store a mapping from common name index
00044 // to fingerprint.  This is used for comparing the fingerprints of
00045 // common names between CFP groups.
00046 typedef Table<IntKey,FP::Tag>::Default CommonTagTbl;
00047 
00048 static bool OpenFile(const Text fname, /*OUT*/ ifstream &ifs)
00049   throw (FS::Failure)
00050 /* Open the file named "fname" for reading. If successful, set "ifs" to a
00051    stream on the file and return true. If the file does not exist, print an
00052    error message and return false. If any other error occurs, throw
00053    "FS::Failure".
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 /* Open and read the MultiPKFile named by the file "nm", and print out an
00076    ASCII representation of it to "os". If "nm" is a relative path, first
00077    prepend the pathname of the cache server's stable cache. Print out a
00078    verbose version if "verbose" is true. */
00079 {
00080     // form the filename
00081     Text fname(nm);
00082     if (nm[0] != '/') {
00083         fname = Config_SCachePath + '/' + fname;
00084     }
00085 
00086     // open the file
00087     ifstream ifs;
00088     if (!OpenFile(fname, /*OUT*/ ifs)) return;
00089 
00090     try {
00091         // read it (including the PKFiles)
00092         SMultiPKFileRep::Header hdr(ifs);
00093         hdr.ReadEntries(ifs);
00094         hdr.ReadPKFiles(ifs);
00095         FS::Close(ifs);
00096 
00097         // print it
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             // write PKFile info
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 // Quote HTML metacharacters ('<', '>', '"', '&') in the given text
00120 // string.
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       // Earliest character needing quoting is a less-than
00133       if((ltPos >= 0) &&
00134          ((gtPos == -1) || (gtPos > ltPos)) &&
00135          ((quotPos == -1) || (quotPos > ltPos)) &&
00136          ((ampPos == -1) || (ampPos > ltPos)))
00137         {
00138           // Copy everything up to the less-than
00139           result += original.Sub(doneCount, ltPos - doneCount);
00140           // Insert the quoted less-than.
00141           result += "&lt;";
00142           // Advance the doneCount;
00143           doneCount = ltPos+1;
00144         }
00145       // Earliest character needing quoting is a greater-than
00146       else if((gtPos >= 0) &&
00147               ((ltPos == -1) || (ltPos > gtPos)) &&
00148               ((quotPos == -1) || (quotPos > gtPos)) &&
00149               ((ampPos == -1) || (ampPos > gtPos)))
00150         {
00151           // Copy everything up to the greater-than
00152           result += original.Sub(doneCount, gtPos - doneCount);
00153           // Insert the quoted greater-than.
00154           result += "&gt;";
00155           // Advance the doneCount;
00156           doneCount = gtPos+1;
00157         }
00158       // Earliest character needing quoting is a double quote
00159       else if((quotPos >= 0) &&
00160               ((ltPos == -1) || (ltPos > quotPos)) &&
00161               ((gtPos == -1) || (gtPos > quotPos)) &&
00162               ((ampPos == -1) || (ampPos > quotPos)))
00163         {
00164           // Copy everything up to the double quote
00165           result += original.Sub(doneCount, quotPos - doneCount);
00166           // Insert the quoted double quote.
00167           result += "&quot;";
00168           // Advance the doneCount;
00169           doneCount = quotPos+1;
00170         }
00171       // Earliest character needing quoting is an ampersand
00172       else if((ampPos >= 0) &&
00173               ((ltPos == -1) || (ltPos > ampPos)) &&
00174               ((gtPos == -1) || (gtPos > ampPos)) &&
00175               ((quotPos == -1) || (quotPos > ampPos)))
00176         {
00177           // Copy everything up to the ampersand
00178           result += original.Sub(doneCount, ampPos - doneCount);
00179           // Insert the quoted ampersand.
00180           result += "&amp;";
00181           // Advance the doneCount;
00182           doneCount = ampPos+1;
00183         }
00184       // No characters needing quoting found: copy the remainder of
00185       // the string to the result.
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 // Return an indentation string for a particular level of indentation.
00198 static Text Indent(unsigned int level)
00199 {
00200   // This holds indentation strings for different levels of
00201   // indentation
00202   static TextSeq l_IndentTexts;
00203 
00204   // Add indentation strings up to the level requested
00205   while(level >= l_IndentTexts.size())
00206     {
00207       unsigned int new_level = l_IndentTexts.size();
00208       // Note: each level of indentation is 2 spaces.
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   // Return the indentation string for the requested level.
00221   return l_IndentTexts.get(level);
00222 }
00223 
00224 extern "C"
00225 {
00226   // Compare two paths of two free variables.  Used with qsort(3) to
00227   // sort lists of free variables by path to make them easier to read.
00228   static int comparePaths(const void *a, const void *b)
00229   {
00230     // Do pointer conversion to get at the Text data.
00231     Text *ta = *((Text **) a), *tb = *((Text **) b);
00232 
00233     // Check to see if one of the paths starts with "./" and the other
00234     // doesn't.  Sort dot paths after non-dot paths.
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     // If both or neither path starts with "./", compare them lexically.
00247     return strcmp(ta->cchars() + 2, tb->cchars() + 2);
00248   }
00249 }
00250 
00251 // Print an HTML table show a set of free variables.
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   // Gather up the names into a separate array so that we can sort
00259   // them by path.
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   // Sort the names by path.
00271   qsort(nameArray, nameTotal, sizeof(Text *), comparePaths);
00272 
00273   // Print the sorted names in a table
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       // For those dependency types the evaluator uses, add a not
00290       // about the meaning of the dependency
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 // Print the standard beginning of an HTML file
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   // Return the initial indent level
00330   return 2;
00331 }
00332 
00333 // Print the standard end of an HTML file
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   // Text string used to identify which kind of URL pattern this is.
00350   // Determined by the presence of certain arguments.
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           // Copy everything up to the percent sign
00378           result += pattern.Sub(doneCount, pctPos - doneCount);
00379 
00380           switch (pattern[pctPos+1])
00381             {
00382             case 'm':
00383               // %m -> PKPrefix
00384               result += pfx.Pathname(PKPrefix::Granularity(),
00385                                      PKPrefix::Granularity());
00386               pfx_included = true;
00387               break;
00388             case 'p':
00389               // %p -> PK with _ between words
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               // %n -> namesEpoch
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               // %c -> CFP with _ between words
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               // %i -> cache index
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               // % followed by any other character will be left
00465               // unmodified.
00466               result += pattern.Sub(pctPos, 2);
00467               break;
00468             }
00469 
00470           // Advance doneCount
00471           doneCount = pctPos+2;
00472         }
00473       // No more escape sequences: copy the remainder of the pattern
00474       // to the result.
00475       else
00476         {
00477           result += pattern.Sub(doneCount);
00478           doneCount = patternLen;
00479         }
00480     }
00481 
00482   // Make sure we included enough information to be able to identify
00483   // whatever the URL is for.
00484   if(ci != 0)
00485     {
00486       // CI provided means this is a URL for a cache entry
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       // CFP provided means this is a URL for a CFP group
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       // PK included means this is a URL for a PKFile
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       // Otherwise, it must be for a MultiPKFile
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 // Generate an HTML filename for a specific MultiPKFile
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 // Generate an HTML filename for a specific PKFile
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 // Generate an HTML filename for a specific common fingerprint group
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 // Generate an HTML filename for a specific cache entry
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                           // Note: no namesEpoch or CFP
00647                           0, 0,
00648                           &ci);
00649 }
00650 
00651 // Combine a directory and a relative path below it, adding a path
00652 // separator if neccessary.
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 // Each level will create one of these to rpresent its state.  This
00666 // primarily it easier to pass this state down to lower levels of the
00667 // HTML generation for adding index entries at higher levels.
00668 struct HTMLFileInfo
00669 {
00670   // Title of this HTML file, used for 
00671   Text title;
00672 
00673   // Filename of this HTML file
00674   Text fname;
00675 
00676   // URL used when referencing this page
00677   Text url;
00678 
00679   // The stream used for writing this THML file
00680   ofstream out;
00681 
00682   // Current indent level in this HTML file
00683   unsigned int indent_level;
00684 
00685   // Get the current level of indentation
00686   inline Text indent()
00687   {
00688     return Indent(this->indent_level);
00689   }
00690   // Get the current level of indentation and then increase it
00691   inline Text indentOpen()
00692   {
00693     return Indent((this->indent_level)++);
00694   }
00695   // Decrease the level of indentation and then get the new level of
00696   // indentation
00697   inline Text indentClose()
00698   {
00699     return Indent(--(this->indent_level));
00700   }
00701 };
00702 
00703 // Generate an HTML file representation of a cache entry
00704 static void PrintCacheEntryHTML(const Text &out_dir, bool print_fnames,
00705                                 // MultiPKFile HTML state
00706                                 HTMLFileInfo &mpk_html,
00707                                 // PKFile HTML state
00708                                 HTMLFileInfo &pkfile_html,
00709                                 // CFP group HTML state
00710                                 HTMLFileInfo &cfp_html,
00711                                 // The header entry for our PKFile
00712                                 SMultiPKFileRep::HeaderEntry *he,
00713                                 // The cache entry to be printed
00714                                 CE::T *entry,
00715                                 // Set of uncommon names that are
00716                                 // common to all entries in the same
00717                                 // CFP group as this entry
00718                                 BitVector &uncommonCommon,
00719                                 bool uncommonCommon_empty)
00720   throw (FS::EndOfFile, FS::Failure)
00721 {
00722   HTMLFileInfo ce_html;
00723 
00724   // Determine the HTML filename and open it
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   // Set the URL for this page
00731   ce_html.url = CacheEntryURL(he->pk, entry->CI());
00732 
00733   // Set the title for the document
00734   {
00735     OBufStream l_title;
00736     l_title << "Cache entry, index = " << entry->CI();
00737     ce_html.title = l_title.str();
00738   }
00739 
00740   // Print the HTML opener
00741   ce_html.indent_level = StartHTML(ce_html.out, ce_html.title);
00742 
00743   // Add an index entry for this cache entry up in the MultiPKFile,
00744   // PKFile, and CFP group HTML
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     // Hyperlinks up
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     // Repeat the title in a section header
00768     << ce_html.indent() << "<h1>" << ce_html.title << "</h1>" << endl;
00769 
00770   // If this is the only entry in this CFP group, just print its
00771   // uncommon FVs.
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       // Find and print the set of uncommon names that only this entry
00794       // uses.
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   // Child cache entries
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   // Derived indecies
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   // Value size
00882   ce_html.out
00883     << ce_html.indent() << "<p>Stored value size: " << value->len
00884     << " bytes.</p>" << endl;
00885 
00886   // Value PrefixTbl size
00887   ce_html.out
00888     << ce_html.indent() << "<p>Value PrefixTbl size: "
00889     << value->prefixTbl.NumArcs() << " entries.";
00890   // If the size of this PrexiTbl seems overly
00891   // large, include a message about its maximum
00892   // possible size.
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   // Finish the HTML, flush and close the file.
00906   EndHTML(ce_html.out);
00907   ce_html.out.flush();
00908   ce_html.out.close();
00909 }
00910 
00911 // Generate an HTML file representation of a common fingerprint group.
00912 // Also, call PrintCacheEntryHTML to generate HTML files for the cache
00913 // entries in this CFP group.
00914 static void PrintCFPGroupHTML(const Text &out_dir, bool print_fnames,
00915                               // MultiPKFile HTML state
00916                               HTMLFileInfo &mpk_html,
00917                               // PKFile HTML state
00918                               HTMLFileInfo &pkfile_html,
00919                               // The MultPKFile header entry for our PKFile
00920                               SMultiPKFileRep::HeaderEntry *he,
00921                               // Our index within the PKFile
00922                               unsigned int cfp_index,
00923                               // The fingerprints of the common names
00924                               // for all CFP groups in this PKFile
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   // Determine the HTML filename and open it
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   // Set the URL for this page
00939   cfp_html.url = CFPGroupURL(he->pk, he->pkfile->NamesEpoch(), cfp);
00940 
00941   // Set the title for the document
00942   {
00943     OBufStream l_title;
00944     l_title << "Common fingerprint Group " << cfp_index << ": " << cfp;
00945     cfp_html.title = l_title.str();
00946   }
00947 
00948   // Print the HTML opener
00949   cfp_html.indent_level = StartHTML(cfp_html.out, cfp_html.title);
00950 
00951   // Add an index entry for this CFP group up in the MultiPKFile and
00952   // PKFile HTML
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     // Hyperlink up the MultiPKFile
00964     << cfp_html.indent() << "Up: <a href=\"" << mpk_html.url
00965     << "\">" << mpk_html.title << "</a><br>" << endl
00966     // Hyperlink up the PKFile
00967     << cfp_html.indent() << "Up: <a href=\"" << pkfile_html.url
00968     << "\">" << pkfile_html.title << "</a><br>" << endl
00969     << cfp_html.indent() << "<hr>" << endl
00970     // Repeat the title in a section header
00971     << cfp_html.indent() << "<h1>" << cfp_html.title << "</h1>" << endl;
00972 
00973   // Determine and display which common names have different
00974   // fingerprintsin other CFP groups
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       // Compare the fingerprints of the commonNames for this CFP with
00988       // that of each other CFP group, printing a table which shows
00989       // which names have different values.
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           // Loop over the common names and find the set of differing
01003           // commonNames.
01004           BitVector commonDiff;
01005           BVIter commonIter(*(he->pkfile->CommonNames()));
01006           int commonIndex;
01007           while(commonIter.Next(commonIndex))
01008             {
01009               // Get the fingerprint of this name in this CFP group
01010               // and the other CFP group.
01011               FP::Tag myFP, theirFP;
01012               bool inTbl = commonTags[cfp_index].Get(commonIndex,
01013                                                      /*OUT*/myFP);
01014               assert(inTbl);
01015               inTbl = commonTags[cfp_j].Get(commonIndex,
01016                                             /*OUT*/theirFP);
01017               assert(inTbl);
01018 
01019               // Remember if they're different
01020               if(myFP != theirFP)
01021                 {
01022                   commonDiff.Set(commonIndex);
01023                 }
01024             }
01025 
01026           // Print a table showing the differing dependencies
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           // Close this table cell and row
01034           cfp_html.out << cfp_html.indentClose() << "</td>" << endl
01035                        << cfp_html.indentClose() << "</tr>" << endl;
01036         }
01037       // Close the table
01038       cfp_html.out << cfp_html.indentClose() << "</table>" << endl;
01039 
01040     }
01041   
01042   // Get the list of cache entries in this CFP group
01043   CE::List *list;
01044   bool inTbl = he->pkfile->OldEntries()->Get(cfp, /*OUT*/ list);
01045   assert(inTbl);
01046   unsigned int entry_count = 1;
01047 
01048   // Used to find the set on uncommon names common to all entries
01049   // in this CFP group (if there's more than one entry).
01050   BitVector uncommonCommon;
01051   bool uncommonCommon_empty = true;
01052 
01053   // If there's more than one entry in this CFP group...
01054   if(list->Tail() != 0)
01055     {
01056       // Loop over the entries in this CFP group
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           // uncommonCommon becomes the intersection of the
01064           // uncommonNames of all entries in thie CFP group
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           // Count entries while we do this
01078           entry_count++;
01079         }
01080 
01081       // If there were any uncommon names common across all
01082       // entries in thie CFP group, add a table showing them.
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   // Start index list for cache entries in our HTML file and the
01105   // MultiPKFile and PKFile HTML files.
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   // Now print each entry
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   // Close index lists for cache entries
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   // Finish the HTML, flush and close the file.
01138   EndHTML(cfp_html.out);
01139   cfp_html.out.flush();
01140   cfp_html.out.close();
01141 }
01142 
01143 // Generate an HTML file representation of a PKFile.  Also, call
01144 // PrintCFPGroupHTML to generate HTML files for the common fingerprint
01145 // groups in this PKFile.
01146 static void PrintPKFileHTML(const Text &out_dir, bool print_fnames,
01147                             // MultiPKFile HTML state
01148                             HTMLFileInfo &mpk_html,
01149                             // Our index within the MultiPKFile
01150                             unsigned int pkfile_index,
01151                             // The MPKFile header entry for this PKFile
01152                             SMultiPKFileRep::HeaderEntry *he)
01153   throw (FS::EndOfFile, FS::Failure)
01154 {
01155   HTMLFileInfo pkfile_html;
01156 
01157   // Determine the HTML filename and open it
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   // Set the URL for this page
01164   pkfile_html.url = PKFileURL(he->pk);
01165 
01166   // Set the title for the document
01167   {
01168     OBufStream l_title;
01169     l_title << "PKFile " << pkfile_index << ": " << he->pk;
01170     pkfile_html.title = l_title.str();
01171   }
01172 
01173   // Print the HTML opener
01174   pkfile_html.indent_level = StartHTML(pkfile_html.out, pkfile_html.title);
01175 
01176   // Put together an HTML bit for this PKFile's sourceFunc, even in
01177   // the case where it's not set.
01178   Text sourceFunc = ((he->pkfile->SourceFunc() == 0)
01179                      ? Text("<i>UNKNOWN</i>")
01180                      : (Text("<tt>")+
01181                         HTMLQuote(*(he->pkfile->SourceFunc()))+
01182                         "</tt>"));
01183 
01184   // Add an index entry for this PKFile up in the MultiPKFile HTML
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     // Hyperlink up the MultiPKFile
01194     << pkfile_html.indent() << "Up: <a href=\"" << mpk_html.url
01195     << "\">" << mpk_html.title << "</a>" << endl
01196     << pkfile_html.indent() << "<hr>" << endl
01197     // Repeat the title in a section header
01198     << pkfile_html.indent() << "<h1>" << pkfile_html.title << "</h1>" << endl
01199     // Source function for this PKFile
01200     << pkfile_html.indent() << "<p>Function:</p>" << endl
01201     << pkfile_html.indent() << "<blockquote>" << sourceFunc
01202     << "</blockquote>" << endl
01203     // Epochs
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     // Introduction of common secondary dependencies
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   // Loop over CFP groups, gathering the fingerprints of the common
01219   // names from each one.  This will be used to show for each CFP
01220   // group which common names differ from other groups.
01221   CommonTagTbl *commonTags = NEW_ARRAY(CommonTagTbl, he->pkhdr->num);
01222   for(int cfp_i = 0; cfp_i < he->pkhdr->num; cfp_i++)
01223     {
01224       // Get the first cache entry in CFP group cfp_i
01225       CE::List *list;
01226       bool inTbl =
01227         he->pkfile->OldEntries()->Get(he->pkhdr->entry[cfp_i].cfp,
01228                                       /*OUT*/ list);
01229       assert(inTbl);
01230       assert(list != 0);
01231       CE::T *entry = list->Head();
01232       assert(entry != 0);
01233 
01234       // Loop over the common names
01235       BVIter commonIter(*(he->pkfile->CommonNames()));
01236       int commonIndex;
01237       while(commonIter.Next(commonIndex))
01238         {
01239           // Find the index of this name in this entry's FP list.
01240           int fpsIndex = commonIndex;
01241           if(entry->IMap() != 0)
01242             {
01243               short temp;
01244               inTbl = entry->IMap()->Get(commonIndex, /*OUT*/ temp);
01245               assert(inTbl);
01246               fpsIndex = temp;
01247             }
01248 
01249           // Remember the tag of this common name in this CFP group.
01250           inTbl = commonTags[cfp_i].Put(commonIndex,
01251                                         entry->FPs()->fp[fpsIndex]);
01252           assert(!inTbl);
01253         }
01254     }
01255 
01256   // Start index list for CFP groups in our HTML file and the
01257   // MultiPKFile HTML file.
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   // Loop over the CFP groups
01268   for(int cfp_i = 0; cfp_i < he->pkhdr->num; cfp_i++)
01269     {
01270       // Generate the HTML file for the CFP group.
01271       PrintCFPGroupHTML(out_dir, print_fnames,
01272                         mpk_html, pkfile_html,
01273                         he, cfp_i, commonTags);
01274     }
01275 
01276   // Close index lists for CFP groups
01277   pkfile_html.out << pkfile_html.indentClose() << "</ul>" << endl;
01278   mpk_html.out << mpk_html.indentClose() << "</ul>" << endl;
01279 
01280   // Finish the HTML, flush and close the file.
01281   EndHTML(pkfile_html.out);
01282   FS::Close(pkfile_html.out);
01283 }
01284 
01285 // Generate an HTML file representation of a MultiPKFile.  Also, call
01286 // PrintPKFileHTML to generate HTML files for the PKFiles in this
01287 // MultiPKFile.
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     // form the filename
01293     Text fname(nm);
01294     if (nm[0] != '/') {
01295         fname = Config_SCachePath + '/' + fname;
01296     }
01297 
01298     // open the MultiPKFile
01299     ifstream ifs;
01300     if (!OpenFile(fname, /*OUT*/ ifs)) return;
01301 
01302     try {
01303         // read it (including the PKFiles)
01304         SMultiPKFileRep::Header hdr(ifs);
01305         hdr.ReadEntries(ifs);
01306         hdr.ReadPKFiles(ifs);
01307         FS::Close(ifs);
01308 
01309         HTMLFileInfo mpk_html;
01310 
01311         // Determine the HTML filename and open it
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         // Set the URL for this page
01320         mpk_html.url = MPKFileURL(pfx);
01321 
01322         // Set the title for the document
01323         {
01324           OBufStream l_title;
01325           l_title << "MultiPKFile " << HTMLQuote(fname);
01326           mpk_html.title = l_title.str();
01327         }
01328 
01329         // Print the HTML opener
01330         mpk_html.indent_level = StartHTML(mpk_html.out, mpk_html.title);
01331 
01332         mpk_html.out
01333           // Repeat the title in a section header
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         // Loop over the PKFiles, generating HTML for each one
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             // Note: this will add entries to the index in out HTML
01346             // file as well.
01347             PrintPKFileHTML(out_dir, print_fnames, mpk_html, i, he);
01348         }
01349 
01350         // Finish the index.
01351         mpk_html.out
01352           << mpk_html.indentClose() << "</ul>" << endl;
01353 
01354         // Finish the HTML, flush and close the file.
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     // process command-line switch(es)
01381     int arg = 1;
01382     for (/*SKIP*/; 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     // process file arguments
01417     if (argc - arg < 1) {
01418         ExitProgram("no file arguments specified");
01419     }
01420     bool firstFile = true; // determines whether to print a separating newline
01421     for (/*SKIP*/; 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 }

Generated on Mon May 8 00:48:35 2006 for Vesta by  doxygen 1.4.2