diff options
Diffstat (limited to 'cmdline/apt-cache.cc')
-rw-r--r-- | cmdline/apt-cache.cc | 176 |
1 files changed, 123 insertions, 53 deletions
diff --git a/cmdline/apt-cache.cc b/cmdline/apt-cache.cc index 0a2c28d23..e847de875 100644 --- a/cmdline/apt-cache.cc +++ b/cmdline/apt-cache.cc @@ -1127,6 +1127,24 @@ bool Dotty(CommandLine &CmdL) // --------------------------------------------------------------------- /* This displays the package record from the proper package index file. It is not used by DumpAvail for performance reasons. */ + +static unsigned char const* skipDescriptionFields(unsigned char const * DescP) +{ + char const * const TagName = "\nDescription"; + size_t const TagLen = strlen(TagName); + while ((DescP = (unsigned char*)strchr((char*)DescP, '\n')) != NULL) + { + if (DescP[1] == ' ') + DescP += 2; + else if (strncmp((char*)DescP, TagName, TagLen) == 0) + DescP += TagLen; + else + break; + } + if (DescP != NULL) + ++DescP; + return DescP; +} bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V) { pkgCache *Cache = CacheFile.GetPkgCache(); @@ -1150,21 +1168,27 @@ bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V) if (PkgF.Open(I.FileName(), FileFd::ReadOnly, FileFd::Extension) == false) return false; - // Read the record - unsigned char *Buffer = new unsigned char[Cache->HeaderP->MaxVerFileSize+1]; - Buffer[V.FileList()->Size] = '\n'; - if (PkgF.Seek(V.FileList()->Offset) == false || - PkgF.Read(Buffer,V.FileList()->Size) == false) + // Read the record (and ensure that it ends with a newline and NUL) + unsigned char *Buffer = new unsigned char[Cache->HeaderP->MaxVerFileSize+2]; + Buffer[Vf->Size] = '\n'; + Buffer[Vf->Size+1] = '\0'; + if (PkgF.Seek(Vf->Offset) == false || + PkgF.Read(Buffer,Vf->Size) == false) { delete [] Buffer; return false; } // Get a pointer to start of Description field - const unsigned char *DescP = (unsigned char*)strstr((char*)Buffer, "Description:"); + const unsigned char *DescP = (unsigned char*)strstr((char*)Buffer, "\nDescription"); + if (DescP != NULL) + ++DescP; + else + DescP = Buffer + Vf->Size; // Write all but Description - if (fwrite(Buffer,1,DescP - Buffer,stdout) < (size_t)(DescP - Buffer)) + size_t const length = DescP - Buffer; + if (length != 0 && FileFd::Write(STDOUT_FILENO, Buffer, length) == false) { delete [] Buffer; return false; @@ -1173,29 +1197,44 @@ bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V) // Show the right description pkgRecords Recs(*Cache); pkgCache::DescIterator Desc = V.TranslatedDescription(); - pkgRecords::Parser &P = Recs.Lookup(Desc.FileList()); - cout << "Description" << ( (strcmp(Desc.LanguageCode(),"") != 0) ? "-" : "" ) << Desc.LanguageCode() << ": " << P.LongDesc(); + if (Desc.end() == false) + { + pkgRecords::Parser &P = Recs.Lookup(Desc.FileList()); + cout << "Description" << ( (strcmp(Desc.LanguageCode(),"") != 0) ? "-" : "" ) << Desc.LanguageCode() << ": " << P.LongDesc(); + cout << std::endl << "Description-md5: " << Desc.md5() << std::endl; + + // Find the first field after the description (if there is any) + DescP = skipDescriptionFields(DescP); + } + // else we have no translation, so we found a lonely Description-md5 -> don't skip it - // Find the first field after the description (if there is any) - for(DescP++;DescP != &Buffer[V.FileList()->Size];DescP++) + // write the rest of the buffer, but skip mixed in Descriptions* fields + while (DescP != NULL) { - if(*DescP == '\n' && *(DescP+1) != ' ') + const unsigned char * const Start = DescP; + const unsigned char *End = (unsigned char*)strstr((char*)DescP, "\nDescription"); + if (End == NULL) { - // write the rest of the buffer - const unsigned char *end=&Buffer[V.FileList()->Size]; - if (fwrite(DescP,1,end-DescP,stdout) < (size_t)(end-DescP)) - { - delete [] Buffer; - return false; - } - - break; + End = &Buffer[Vf->Size]; + DescP = NULL; + } + else + { + ++End; // get the newline into the output + DescP = skipDescriptionFields(End + strlen("Description")); + } + size_t const length = End - Start; + if (length != 0 && FileFd::Write(STDOUT_FILENO, Start, length) == false) + { + delete [] Buffer; + return false; } } - // write a final newline (after the description) + + // write a final newline after the last field cout<<endl; - delete [] Buffer; + delete [] Buffer; return true; } /*}}}*/ @@ -1203,7 +1242,7 @@ bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V) struct ExDescFile { pkgCache::DescFile *Df; - bool NameMatch; + map_ptrloc ID; }; // Search - Perform a search /*{{{*/ @@ -1246,37 +1285,52 @@ bool Search(CommandLine &CmdL) return false; } - ExDescFile *DFList = new ExDescFile[Cache->HeaderP->GroupCount+1]; - memset(DFList,0,sizeof(*DFList)*Cache->HeaderP->GroupCount+1); + size_t const descCount = Cache->HeaderP->GroupCount + 1; + ExDescFile *DFList = new ExDescFile[descCount]; + memset(DFList,0,sizeof(*DFList) * descCount); + + bool PatternMatch[descCount * NumPatterns]; + memset(PatternMatch,false,sizeof(PatternMatch)); // Map versions that we want to write out onto the VerList array. for (pkgCache::GrpIterator G = Cache->GrpBegin(); G.end() == false; ++G) { - if (DFList[G->ID].NameMatch == true) - continue; - - DFList[G->ID].NameMatch = true; - for (unsigned I = 0; I != NumPatterns; I++) + size_t const PatternOffset = G->ID * NumPatterns; + size_t unmatched = 0, matched = 0; + for (unsigned I = 0; I < NumPatterns; ++I) { - if (regexec(&Patterns[I],G.Name(),0,0,0) == 0) - continue; - DFList[G->ID].NameMatch = false; - break; + if (PatternMatch[PatternOffset + I] == true) + ++matched; + else if (regexec(&Patterns[I],G.Name(),0,0,0) == 0) + PatternMatch[PatternOffset + I] = true; + else + ++unmatched; } - - // Doing names only, drop any that dont match.. - if (NamesOnly == true && DFList[G->ID].NameMatch == false) + + // already dealt with this package? + if (matched == NumPatterns) continue; - + + // Doing names only, drop any that don't match.. + if (NamesOnly == true && unmatched == NumPatterns) + continue; + // Find the proper version to use pkgCache::PkgIterator P = G.FindPreferredPkg(); if (P.end() == true) continue; pkgCache::VerIterator V = Plcy->GetCandidateVer(P); if (V.end() == false) - DFList[G->ID].Df = V.TranslatedDescription().FileList(); + { + pkgCache::DescIterator const D = V.TranslatedDescription(); + //FIXME: packages without a description can't be found + if (D.end() == true) + continue; + DFList[G->ID].Df = D.FileList(); + DFList[G->ID].ID = G->ID; + } - if (DFList[G->ID].NameMatch == false) + if (unmatched == NumPatterns) continue; // Include all the packages that provide matching names too @@ -1287,34 +1341,50 @@ bool Search(CommandLine &CmdL) continue; unsigned long id = Prv.OwnerPkg().Group()->ID; - DFList[id].Df = V.TranslatedDescription().FileList(); - DFList[id].NameMatch = true; + pkgCache::DescIterator const D = V.TranslatedDescription(); + //FIXME: packages without a description can't be found + if (D.end() == true) + continue; + DFList[id].Df = D.FileList(); + DFList[id].ID = id; + + size_t const PrvPatternOffset = id * NumPatterns; + for (unsigned I = 0; I < NumPatterns; ++I) + PatternMatch[PrvPatternOffset + I] = PatternMatch[PatternOffset + I]; } } - + LocalitySort(&DFList->Df,Cache->HeaderP->GroupCount,sizeof(*DFList)); // Create the text record parser pkgRecords Recs(*Cache); // Iterate over all the version records and check them - for (ExDescFile *J = DFList; J->Df != 0; J++) + for (ExDescFile *J = DFList; J->Df != 0; ++J) { pkgRecords::Parser &P = Recs.Lookup(pkgCache::DescFileIterator(*Cache,J->Df)); + size_t const PatternOffset = J->ID * NumPatterns; - if (J->NameMatch == false && NamesOnly == false) + if (NamesOnly == false) { string const LongDesc = P.LongDesc(); - J->NameMatch = true; - for (unsigned I = 0; I != NumPatterns; I++) + for (unsigned I = 0; I < NumPatterns; ++I) { - if (regexec(&Patterns[I],LongDesc.c_str(),0,0,0) == 0) + if (PatternMatch[PatternOffset + I] == true) continue; - J->NameMatch = false; - break; + else if (regexec(&Patterns[I],LongDesc.c_str(),0,0,0) == 0) + PatternMatch[PatternOffset + I] = true; } } - - if (J->NameMatch == true) + + bool matchedAll = true; + for (unsigned I = 0; I < NumPatterns; ++I) + if (PatternMatch[PatternOffset + I] == false) + { + matchedAll = false; + break; + } + + if (matchedAll == true) { if (ShowFull == true) { |