00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <Basics.H>
00020 #include <FS.H>
00021 #include <FP.H>
00022
00023
00024 #include <BitVector.H>
00025 #include <FV.H>
00026 #include <CompactFV.H>
00027 #include <TextIO.H>
00028 #include <Debug.H>
00029
00030
00031 #include "SPKFileRep.H"
00032 #include "IntIntTblLR.H"
00033 #include "CacheEntry.H"
00034 #include "VPKFileChkPt.H"
00035 #include "SPKFile.H"
00036
00037 using std::streampos;
00038 using std::ostream;
00039 using std::ifstream;
00040 using std::endl;
00041 using OS::cio;
00042
00043
00044
00045 bool SPKFile::Update(const VPKFileChkPt *chkpt, const BitVector *toDelete,
00046 BitVector* &exCommonNames, BitVector* &exUncommonNames,
00047 BitVector* &packMask, IntIntTblLR* &reMap,
00048 bool &isEmpty) throw ()
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 {
00077
00078 if (chkpt == (VPKFileChkPt *)NULL) {
00079 chkpt = this->CheckPoint();
00080 assert(!(chkpt->hasNewEntries));
00081 } else if (this->sourceFunc == (Text *)NULL) {
00082
00083 this->sourceFunc = chkpt->sourceFunc;
00084 }
00085
00086
00087 assert(chkpt->hasNewEntries || (toDelete != (BitVector *)NULL));
00088 exCommonNames = exUncommonNames = packMask = (BitVector *)NULL;
00089 reMap = (IntIntTblLR *)NULL;
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 BitVector newAllNames, newCommonNames;
00101 int totalEntries = 0;
00102 bool thisDelOne = false;
00103 if (toDelete == (BitVector *)NULL) {
00104
00105
00106 if(this->allNames.len > 0)
00107 newAllNames.SetInterval(0, this->allNames.len - 1);
00108 newAllNames -= this->commonNames;
00109 totalEntries = this->oldEntries.Size();
00110 } else {
00111
00112 ScanCommonTable(this->oldEntries, toDelete,
00113 newAllNames, newCommonNames,
00114 totalEntries, thisDelOne);
00115 }
00116
00117 bool newDelOne = false;
00118 int numCommonEntries = totalEntries;
00119 int numStableEntries = totalEntries;
00120
00121
00122 if (chkpt->newCommon.Size() > 0) {
00123 ScanCommonTable(chkpt->newCommon, toDelete,
00124 newAllNames, newCommonNames,
00125 totalEntries, newDelOne);
00126 numCommonEntries = totalEntries;
00127 }
00128
00129
00130 if (numCommonEntries > 0) {
00131 newAllNames |= this->commonNames;
00132 newCommonNames |= this->commonNames;
00133 }
00134
00135
00136 if (chkpt->newUncommon != (CE::List *)NULL) {
00137 ScanList(chkpt->newUncommon, toDelete,
00138 newAllNames, newCommonNames,
00139 totalEntries, newDelOne);
00140 }
00141
00142
00143 bool newChkptEntries = (totalEntries > numStableEntries);
00144 bool delAny = (thisDelOne || newDelOne);
00145
00146
00147
00148
00149 isEmpty = (totalEntries == 0);
00150 bool isNewPKFile = (this->pkEpoch == 0);
00151
00152
00153
00154
00155
00156
00157
00158 bool pkfileModified = (newChkptEntries || delAny);
00159 if (!pkfileModified) return pkfileModified;
00160
00161
00162 if (isNewPKFile) {
00163
00164
00165
00166
00167 if (!(newCommonNames.IsEmpty())) {
00168 exUncommonNames = NEW_CONSTR(BitVector, (&newCommonNames));
00169 }
00170 } else if (isEmpty) {
00171
00172
00173
00174 exCommonNames = NEW_CONSTR(BitVector, (&(this->commonNames)));
00175 } else {
00176
00177 BitVector bothCommon(&(this->commonNames));
00178 bothCommon &= newCommonNames;
00179
00180
00181 if (bothCommon < this->commonNames) {
00182 exCommonNames = NEW_CONSTR(BitVector, (&(this->commonNames)));
00183 *exCommonNames -= newCommonNames;
00184 }
00185 if (bothCommon < newCommonNames) {
00186 exUncommonNames = NEW_CONSTR(BitVector, (&newCommonNames));
00187 *exUncommonNames -= this->commonNames;
00188 }
00189 }
00190
00191
00192 bool commonNamesChanged =
00193 ((exCommonNames != NULL) || (exUncommonNames != NULL));
00194 if (commonNamesChanged) {
00195 this->commonNames = newCommonNames;
00196 }
00197
00198
00199
00200
00201 if (isEmpty) {
00202
00203
00204 this->allNames.Reset();
00205 this->oldEntries.Init();
00206
00207
00208
00209 packMask = NEW(BitVector);
00210 reMap = NEW_CONSTR(IntIntTblLR, ( 0));
00211 } else {
00212
00213
00214
00215
00216
00217
00218
00219 if (delAny) {
00220 unsigned int nextAvail = newAllNames.NextAvail( false);
00221 assert(nextAvail <= chkpt->allNamesLen);
00222 if (nextAvail < chkpt->allNamesLen) {
00223
00224 packMask = NEW_CONSTR(BitVector, (&newAllNames));
00225 reMap = NEW_CONSTR(IntIntTblLR,
00226 ( chkpt->allNamesLen));
00227 BVIter it(*packMask);
00228 unsigned int k;
00229 for (int i = 0; it.Next( k); i++) {
00230
00231 try
00232 {
00233 bool inTbl = reMap->Put(k, i);
00234 assert(!inTbl);
00235 }
00236 catch(IntIntTblLR::InvalidKey e)
00237 {
00238 cio().start_err() << Debug::Timestamp()
00239 << "INTERNAL ERROR: "
00240 << "IntIntTblLR::InvalidKey caugt in SPKFile::Update"
00241 << endl << " value = " << e.key << endl;
00242 cio().end_err(true);
00243 abort();
00244 }
00245 catch(IntIntTblLR::InvalidValue e)
00246 {
00247 cio().start_err() << Debug::Timestamp()
00248 << "INTERNAL ERROR: "
00249 << "IntIntTblLR::InvalidValue caugt in SPKFile::Update"
00250 << endl << " value = " << e.val << endl;
00251 cio().end_err(true);
00252 abort();
00253 }
00254
00255 }
00256 }
00257 }
00258 assert((packMask == NULL) == (reMap == NULL));
00259 assert((packMask == NULL) || delAny);
00260
00261
00262
00263 for (int i = this->allNames.len; i < chkpt->allNamesLen; i++) {
00264 this->allNames.Append(chkpt->allNames->name[i]);
00265 }
00266
00267 this->allNames.Pack(packMask);
00268
00269
00270 if (isNewPKFile) {
00271
00272
00273 assert(this->oldEntries.Size() == 0);
00274 } else if (thisDelOne || commonNamesChanged) {
00275
00276
00277
00278
00279 assert(this->oldEntries.Size() > 0);
00280 UpdateCommonTable(this->oldEntries, toDelete, exCommonNames,
00281 exUncommonNames, packMask, reMap, true);
00282 }
00283
00284
00285 if (chkpt->hasNewEntries) {
00286 AddEntries(*chkpt, toDelete, exCommonNames, exUncommonNames,
00287 packMask, reMap, true);
00288 }
00289
00290
00291 this->commonNames.Pack(packMask);
00292 }
00293
00294
00295
00296
00297 this->pkEpoch = chkpt->pkEpoch + 1;
00298 this->namesEpoch = chkpt->namesEpoch;
00299 if (reMap != NULL) {
00300
00301 this->namesEpoch++;
00302 }
00303 assert(pkfileModified);
00304 return pkfileModified;
00305 }
00306
00307 VPKFileChkPt *SPKFile::CheckPoint() throw ()
00308 {
00309 VPKFileChkPt *res = NEW(VPKFileChkPt);
00310
00311 res->sourceFunc = this->sourceFunc;
00312 res->pkEpoch = this->pkEpoch;
00313 res->namesEpoch = this->namesEpoch;
00314 res->allNamesLen = this->allNames.len;
00315 res->allNames = &(this->allNames);
00316 return res;
00317 }
00318
00319 void SPKFile::ScanCommonTable(const CFPEntryMap &cfpTbl,
00320 const BitVector *toDelete, BitVector &uncommonJoin,
00321 BitVector &uncommonMeet, int &totalEntries,
00322 bool &delOne) const throw ()
00323 {
00324 if (cfpTbl.Size() > 0) {
00325 CFPEntryIter iter(&cfpTbl);
00326 FP::Tag cfp; CE::List *curr;
00327 while (iter.Next( cfp, curr)) {
00328 ScanList(curr, toDelete, uncommonJoin,
00329 uncommonMeet, totalEntries,
00330 delOne);
00331 }
00332 }
00333 }
00334
00335 void SPKFile::ScanList(const CE::List *head, const BitVector *toDelete,
00336 BitVector &uncommonJoin, BitVector &uncommonMeet,
00337 int &totalEntries, bool &delOne) const throw ()
00338 {
00339 for (const CE::List *curr = head; curr != NULL; curr = curr->Tail()) {
00340 CE::T *ce = curr->Head();
00341 if (toDelete != NULL && toDelete->Read(ce->CI())) {
00342
00343 delOne = true;
00344 } else {
00345
00346 uncommonJoin |= ce->UncommonNames();
00347 if (totalEntries > 0) {
00348
00349 uncommonMeet &= ce->UncommonNames();
00350 } else {
00351
00352 uncommonMeet = ce->UncommonNames();
00353 }
00354 totalEntries++;
00355 }
00356 }
00357 }
00358
00359 CE::List* SPKFile::ExtractEntries( CFPEntryMap &cfpTbl) throw ()
00360 {
00361
00362 CE::List *res = (CE::List *)NULL, *curr;
00363 FP::Tag cfp;
00364 CFPEntryIter iter(&cfpTbl);
00365 while (iter.Next( cfp, curr)) {
00366 while (curr != (CE::List *)NULL) {
00367 res = NEW_CONSTR(CE::List, (curr->Head(), res));
00368 curr = curr->Tail();
00369 }
00370 }
00371
00372 cfpTbl.Init();
00373 return res;
00374 }
00375
00376 void SPKFile::UpdateCommonTable( CFPEntryMap &cfpTbl,
00377 const BitVector *toDelete, const BitVector *exCommonNames,
00378 const BitVector *exUncommonNames, const BitVector *packMask,
00379 const IntIntTblLR *reMap, bool unlazyTag) throw ()
00380
00381
00382 {
00383
00384 assert(cfpTbl.Size() > 0);
00385 assert((packMask == NULL) == (reMap == NULL));
00386
00387
00388 CE::List *existing = ExtractEntries(cfpTbl);
00389
00390
00391
00392 UpdateList(cfpTbl, existing, toDelete, exCommonNames, exUncommonNames,
00393 packMask, reMap, unlazyTag);
00394 }
00395
00396 void SPKFile::AddEntries(const VPKFileChkPt &chkpt, const BitVector *toDelete,
00397 const BitVector *exCommonNames, const BitVector *exUncommonNames,
00398 const BitVector *packMask, const IntIntTblLR *reMap, bool unlazyTag)
00399 throw ()
00400
00401 {
00402 assert((packMask == NULL) == (reMap == NULL));
00403
00404
00405 if (chkpt.newCommon.Size() > 0) {
00406 assert(this->pkEpoch > 0);
00407 CFPEntryIter iter(&(chkpt.newCommon));
00408 FP::Tag cfp; CE::List *ents;
00409 while (iter.Next( cfp, ents)) {
00410 UpdateList(this->oldEntries, ents, toDelete, exCommonNames,
00411 exUncommonNames, packMask, reMap, unlazyTag);
00412 }
00413 }
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423 UpdateList(this->oldEntries, chkpt.newUncommon, toDelete,
00424 (BitVector *)NULL, &commonNames,
00425 packMask, reMap, unlazyTag);
00426 }
00427
00428 void SPKFile::UpdateList( CFPEntryMap &cfpTbl,
00429 const CE::List *ents, const BitVector *toDelete,
00430 const BitVector *exCommonNames, const BitVector *exUncommonNames,
00431 const BitVector *packMask, const IntIntTblLR *reMap, bool unlazyTag)
00432 throw ()
00433
00434 {
00435 for (; ents != (CE::List *)NULL; ents = ents->Tail()) {
00436 CE::T *ce = ents->Head();
00437 if ((toDelete == (BitVector *)NULL) || !(toDelete->Read(ce->CI()))) {
00438
00439
00440
00441 FP::Tag *commonFP = ce->CombineFP(commonNames);
00442
00443
00444 ce->Update(exCommonNames, exUncommonNames, packMask, reMap);
00445
00446
00447 if (unlazyTag) ce->UnlazyUncommonFP();
00448
00449
00450 AddEntryToTable(cfpTbl, *commonFP, ce);
00451 }
00452 }
00453 }
00454
00455 void SPKFile::AddEntryToTable( CFPEntryMap &cfpTbl,
00456 const FP::Tag &cfp, CE::T *ce) const throw ()
00457 {
00458 CE::List *curr;
00459 if (!cfpTbl.Get(cfp, curr)) {
00460 curr = (CE::List *)NULL;
00461 }
00462 curr = NEW_CONSTR(CE::List, (ce, curr));
00463 (void)cfpTbl.Put(cfp, curr);
00464 }
00465
00466
00467
00468
00469 CE::T* SPKFile::Lookup(ifstream &ifs, streampos origin,
00470 int version, const FP::Tag &commonTag, const FP::List &fps)
00471 throw (FS::EndOfFile, FS::Failure)
00472
00473 {
00474
00475 assert(FS::Posn(ifs) == origin);
00476
00477
00478 SPKFileRep::Header hdr(ifs, origin, version, false);
00479
00480
00481 streampos offset = LookupCFP(ifs, origin, version, commonTag, hdr);
00482 if (offset < 0) return (CE::T *)NULL;
00483 FS::Seek(ifs, origin + offset);
00484
00485
00486 CE::T *res;
00487 if (version <= SPKFileRep::SourceFuncVersion) {
00488 res = LookupEntryV1(ifs, fps);
00489 } else {
00490
00491 assert(false);
00492 }
00493 return res;
00494 }
00495
00496
00497 streampos SPKFile::LookupCFP(ifstream &ifs, streampos origin,
00498 int version, const FP::Tag &cfp, const SPKFileRep::Header &hdr)
00499 throw (FS::EndOfFile, FS::Failure)
00500
00501 {
00502 streampos res;
00503 switch (hdr.type) {
00504 case SPKFileRep::HT_List:
00505 if (version <= SPKFileRep::SourceFuncVersion) {
00506 res = LookupCFPInListV1(ifs, origin, cfp, hdr.num);
00507 } else {
00508
00509 assert(false);
00510 }
00511 break;
00512 case SPKFileRep::HT_SortedList:
00513 if (version <= SPKFileRep::SourceFuncVersion) {
00514 res = LookupCFPInSortedListV1(ifs, origin, cfp, hdr.num);
00515 } else {
00516
00517 assert(false);
00518 }
00519 break;
00520 case SPKFileRep::HT_HashTable:
00521 case SPKFileRep::HT_PerfectHashTable:
00522
00523 assert(false);
00524 default:
00525 assert(false);
00526 }
00527 return res;
00528 }
00529
00530
00531 streampos SPKFile::LookupCFPInListV1(ifstream &ifs, streampos origin,
00532 const FP::Tag &cfp, int num) throw (FS::EndOfFile, FS::Failure)
00533
00534 {
00535 for (int i = 0; i < num; i++) {
00536 SPKFileRep::HeaderEntry he(ifs, origin);
00537 if (he.cfp == cfp) {
00538
00539 return he.offset;
00540 }
00541 }
00542 return (-1);
00543 }
00544
00545
00546 streampos SPKFile::LookupCFPInSortedListV1(ifstream &ifs, streampos origin,
00547 const FP::Tag &cfp, int num) throw (FS::EndOfFile, FS::Failure)
00548
00549 {
00550
00551 int lo = 0, hi = num;
00552 streampos base = FS::Posn(ifs);
00553 while (lo < hi) {
00554
00555
00556
00557
00558
00559 int mid = (lo + hi) / 2;
00560 assert(lo <= mid && mid < hi);
00561 FS::Seek(ifs, (base +
00562 (streampos) (mid * SPKFileRep::HeaderEntry::Size())));
00563 SPKFileRep::HeaderEntry midEntry(ifs, origin);
00564
00565
00566 int cmp = Compare(cfp, midEntry.cfp);
00567 if (cmp < 0) {
00568
00569 hi = mid;
00570 } else if (cmp > 0) {
00571
00572 lo = mid + 1;
00573 } else {
00574 return (streampos)(midEntry.offset);
00575 }
00576 }
00577 return (-1);
00578 }
00579
00580
00581 CE::T* SPKFile::LookupEntryV1(ifstream &ifs, const FP::List &fps)
00582 throw (FS::EndOfFile, FS::Failure)
00583
00584 {
00585
00586 SPKFileRep::UShort numEntries;
00587 FS::Read(ifs, (char *)(&numEntries), sizeof(numEntries));
00588
00589
00590 for (int i = 0; i < numEntries; i++) {
00591
00592 CE::T *ce = NEW_CONSTR(CE::T, (ifs));
00593 assert(ce->UncommonFPIsUnlazied());
00594
00595
00596 if (ce->FPMatch(fps)) {
00597 return ce;
00598 }
00599 }
00600 return (CE::T *)NULL;
00601 }
00602
00603
00604
00605 void SPKFile::Read(ifstream &ifs, streampos origin, int version,
00606 SPKFileRep::Header* &hdr, bool readEntries, bool readImmutable)
00607 throw (FS::EndOfFile, FS::Failure)
00608
00609 {
00610
00611 assert(FS::Posn(ifs) == origin);
00612
00613
00614 if (readEntries) {
00615
00616 hdr = NEW_CONSTR(SPKFileRep::Header,
00617 (ifs, origin,
00618 version, true));
00619 } else {
00620 hdr = (SPKFileRep::Header *)NULL;
00621 SPKFileRep::Header::Skip(ifs, origin, version);
00622 }
00623
00624
00625 if (version >= SPKFileRep::SourceFuncVersion) {
00626 Text *temp = NEW(Text);
00627 TextIO::Read(ifs, *temp);
00628 this->sourceFunc = temp;
00629 if (this->sourceFunc->Length() == 0) this->sourceFunc = (Text *)NULL;
00630 } else {
00631 this->sourceFunc = (Text *)NULL;
00632 }
00633 FS::Read(ifs, (char *)(&(this->pkEpoch)), sizeof(this->pkEpoch));
00634 FS::Read(ifs, (char *)(&(this->namesEpoch)), sizeof(this->namesEpoch));
00635 CompactFV::List compactFV(ifs);
00636 this->allNames.Grow( compactFV.num + 5);
00637 compactFV.ToFVList( this->allNames);
00638 this->commonNames.Read(ifs);
00639
00640
00641 if (readEntries) {
00642
00643 for (int i = 0; i < hdr->num; i++) {
00644
00645 assert(FS::Posn(ifs) == origin + (streampos) hdr->entry[i].offset);
00646
00647
00648 CE::List *entryList = this->ReadEntries(ifs, readImmutable);
00649
00650
00651 bool inTbl = this->oldEntries.Put(hdr->entry[i].cfp, entryList);
00652 assert(!inTbl);
00653 }
00654 }
00655 }
00656
00657 CE::List *SPKFile::ReadEntries(ifstream &ifs, bool readImmutable)
00658 throw (FS::EndOfFile, FS::Failure)
00659
00660 {
00661
00662 SPKFileRep::UShort numEntries;
00663 FS::Read(ifs, (char *)(&numEntries), sizeof(numEntries));
00664
00665
00666
00667
00668
00669 CE::T *entry;
00670 CE::List *head = (CE::List *)NULL, *prev, *curr;
00671
00672
00673 for (int i = 0; i < numEntries; i++) {
00674 entry = NEW_CONSTR(CE::T, (ifs, readImmutable));
00675 curr = NEW_CONSTR(CE::List, (entry, (CE::List *)NULL));
00676 if (head == (CE::List *)NULL)
00677 head = curr;
00678 else
00679 prev->SetTail(curr);
00680 prev = curr;
00681 }
00682
00683
00684 for (curr = head; curr != (CE::List *)NULL; curr = curr->Tail()) {
00685 curr->Head()->ReadExtras(ifs);
00686 }
00687 return head;
00688 }
00689
00690 void SPKFile::Write(ifstream &ifs, ostream &ofs, streampos origin,
00691 SPKFileRep::Header* &hdr) const
00692 throw (FS::Failure)
00693
00694 {
00695
00696 FP::Tag key;
00697 CE::List *entryList;
00698
00699
00700 hdr = NEW(SPKFileRep::Header);
00701 hdr->num = this->oldEntries.Size();
00702 hdr->entry = NEW_ARRAY(SPKFileRep::HeaderEntry, hdr->num);
00703 CFPEntryIter it(&(this->oldEntries));
00704 int i;
00705 for (i = 0; it.Next( key, entryList); i++) {
00706 assert(i < hdr->num);
00707 hdr->entry[i].cfp = key;
00708 }
00709
00710
00711 hdr->Write(ofs, origin);
00712
00713
00714 const Text *t = (this->sourceFunc != (Text *)NULL)
00715 ? this->sourceFunc : NEW(Text);
00716 TextIO::Write(ofs, *t);
00717 FS::Write(ofs, (char *)(&(this->pkEpoch)), sizeof(this->pkEpoch));
00718 FS::Write(ofs, (char *)(&(this->namesEpoch)), sizeof(this->namesEpoch));
00719 try
00720 {
00721 CompactFV::List compactFV(this->allNames);
00722 compactFV.Write(ofs);
00723 }
00724
00725
00726
00727
00728
00729 catch(PrefixTbl::Overflow)
00730 {
00731 cio().start_err() << Debug::Timestamp()
00732 << "INTERNAL ERROR: "
00733 << "PrefixTbl overflow in writing free variables to "
00734 << "stable PKFile:" << endl
00735 << " pk = " << pk << endl
00736 << " sourceFunc = " << ((this->sourceFunc != (Text *)NULL)
00737 ? this->sourceFunc->cchars()
00738 : "<UNKNOWN>") << endl
00739 << "(This means you've exceeded internal limits of the" << endl
00740 << "cache server, and you may have to erase your cache.)" << endl;
00741 cio().end_err(true);
00742
00743 abort();
00744 }
00745 this->commonNames.Write(ofs);
00746
00747
00748 for (i = 0; i < hdr->num; i++) {
00749 SPKFileRep::HeaderEntry *entryPtr = &(hdr->entry[i]);
00750 entryPtr->offset = FS::Posn(ofs) - origin;
00751 bool inTbl = this->oldEntries.Get(entryPtr->cfp, entryList);
00752 assert(inTbl);
00753 WriteEntries(ifs, ofs, entryList);
00754 }
00755 }
00756
00757 void SPKFile::WriteEntries(ifstream &ifs, ostream &ofs, CE::List *entryList)
00758 const throw (FS::Failure)
00759
00760 {
00761
00762 SPKFileRep::UShort numEntries = CE::List::Length(entryList);
00763 FS::Write(ofs, (char *)(&numEntries), sizeof(numEntries));
00764
00765
00766 CE::List *curr;
00767 for (curr = entryList; curr != NULL; curr = curr->Tail()) {
00768 {
00769 unsigned int missing;
00770 if(curr->Head()->CheckUsedNames(&(this->commonNames), missing))
00771 {
00772 cio().start_err() << Debug::Timestamp()
00773 << "INTERNAL ERROR: "
00774 << "Detected incorrect commonNames|uncommonNames:" << endl
00775 << " pk = " << pk << endl
00776 << " ci = " << curr->Head()->CI() << endl
00777 << " missing name = " << missing << endl << endl
00778 << " (Please report this as a bug.)" << endl;
00779 cio().end_err(true);
00780
00781 abort();
00782 }
00783 }
00784
00785 curr->Head()->Write(ofs, &ifs);
00786 }
00787
00788
00789 for (curr = entryList; curr != NULL; curr = curr->Tail()) {
00790 curr->Head()->WriteExtras(ofs);
00791 }
00792 }
00793
00794 static void SPKFile_WriteBanner(ostream &os, char c, int width) throw ()
00795 {
00796 os << "// "; width -= 3;
00797 for (int i = 0; i < width; i++) os << c;
00798 os << endl;
00799 }
00800
00801 void SPKFile::Debug(ostream &os, const SPKFileRep::Header &hdr,
00802 streampos origin, bool verbose) const throw ()
00803 {
00804 const int BannerWidth = 75;
00805
00806
00807 os << endl;
00808 SPKFile_WriteBanner(os, '+', BannerWidth);
00809 os << "// <PKFile> (offset " << origin << ")" << endl;
00810 SPKFile_WriteBanner(os, '+', BannerWidth);
00811 if (!verbose) {
00812 os << endl << "pk = " << pk << endl;
00813 } else {
00814 os << "pk = " << pk << endl;
00815 }
00816
00817
00818 hdr.Debug(os, verbose);
00819 int i;
00820 for (i = 0; i < hdr.num; i++) {
00821 hdr.entry[i].Debug(os, verbose);
00822 }
00823
00824 if (verbose) {
00825
00826 os << endl << "// <PKFHeaderTail>" << endl;
00827 os << "sourceFunc = " <<
00828 ((this->sourceFunc != (Text *)NULL)
00829 ? this->sourceFunc->cchars()
00830 : "<UNKNOWN>")
00831 << endl;
00832 os << "pkEpoch = " << this->pkEpoch << endl;
00833 os << "nmsEpoch = " << this->namesEpoch << endl;
00834 os << "allNames =" << endl;
00835 this->allNames.Print(os, 2, &(this->commonNames));
00836 os << "commonNms = {" << endl;
00837 this->commonNames.PrintAll(os, 4);
00838 os << " } (" << this->commonNames.Cardinality() << " total)" << endl;
00839 }
00840
00841
00842 for (i = 0; i < hdr.num; i++) {
00843
00844 os << endl;
00845 if (verbose) {
00846 SPKFile_WriteBanner(os, '-', BannerWidth);
00847 }
00848 os << "// <PKEntries> (offset " << hdr.entry[i].offset << ")" << endl;
00849 CE::List *list;
00850 bool inTbl = this->oldEntries.Get(hdr.entry[i].cfp, list);
00851 assert(inTbl);
00852 os << "numEntries = " << CE::List::Length(list) << endl;
00853
00854 if (verbose) {
00855
00856 CE::List *curr;
00857 int i;
00858 for (curr=list, i=1; curr != NULL; curr=curr->Tail(), i++) {
00859 os << endl << "// <PKEntry> (#" << i << ")" << endl;
00860 curr->Head()->Debug(os);
00861 }
00862
00863
00864 for (curr=list, i=1; curr != NULL; curr=curr->Tail(), i++) {
00865 os << endl << "// <PKEntryExtra> (#" << i << ")" << endl;
00866 curr->Head()->DebugExtras(os);
00867 }
00868 }
00869 }
00870 }