|
@@ -16,6 +16,7 @@
|
|
|
#include <apt-private/private-cacheset.h>
|
|
|
#include <apt-private/private-output.h>
|
|
|
#include <apt-private/private-search.h>
|
|
|
+#include <apt-private/private-show.h>
|
|
|
|
|
|
#include <string.h>
|
|
|
#include <iostream>
|
|
@@ -27,7 +28,7 @@
|
|
|
#include <apti18n.h>
|
|
|
/*}}}*/
|
|
|
|
|
|
-bool FullTextSearch(CommandLine &CmdL) /*{{{*/
|
|
|
+static bool FullTextSearch(CommandLine &CmdL) /*{{{*/
|
|
|
{
|
|
|
pkgCacheFile CacheFile;
|
|
|
pkgCache *Cache = CacheFile.GetPkgCache();
|
|
@@ -56,8 +57,6 @@ bool FullTextSearch(CommandLine &CmdL) /*{{{*/
|
|
|
Patterns.push_back(pattern);
|
|
|
}
|
|
|
|
|
|
- bool const NamesOnly = _config->FindB("APT::Cache::NamesOnly", false);
|
|
|
-
|
|
|
std::map<std::string, std::string> output_map;
|
|
|
|
|
|
LocalitySortedVersionSet bag;
|
|
@@ -76,6 +75,7 @@ bool FullTextSearch(CommandLine &CmdL) /*{{{*/
|
|
|
else
|
|
|
format += " ${LongDescription}\n";
|
|
|
|
|
|
+ bool const NamesOnly = _config->FindB("APT::Cache::NamesOnly", false);
|
|
|
int Done = 0;
|
|
|
std::vector<bool> PkgsDone(Cache->Head().PackageCount, false);
|
|
|
for ( ;V != bag.end(); ++V)
|
|
@@ -127,3 +127,203 @@ bool FullTextSearch(CommandLine &CmdL) /*{{{*/
|
|
|
return true;
|
|
|
}
|
|
|
/*}}}*/
|
|
|
+// LocalitySort - Sort a version list by package file locality /*{{{*/
|
|
|
+static int LocalityCompare(const void * const a, const void * const b)
|
|
|
+{
|
|
|
+ pkgCache::VerFile const * const A = *(pkgCache::VerFile const * const * const)a;
|
|
|
+ pkgCache::VerFile const * const B = *(pkgCache::VerFile const * const * const)b;
|
|
|
+
|
|
|
+ if (A == 0 && B == 0)
|
|
|
+ return 0;
|
|
|
+ if (A == 0)
|
|
|
+ return 1;
|
|
|
+ if (B == 0)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ if (A->File == B->File)
|
|
|
+ return A->Offset - B->Offset;
|
|
|
+ return A->File - B->File;
|
|
|
+}
|
|
|
+void LocalitySort(pkgCache::VerFile ** const begin, unsigned long long const Count,size_t const Size)
|
|
|
+{
|
|
|
+ qsort(begin,Count,Size,LocalityCompare);
|
|
|
+}
|
|
|
+static void LocalitySort(pkgCache::DescFile ** const begin, unsigned long long const Count,size_t const Size)
|
|
|
+{
|
|
|
+ qsort(begin,Count,Size,LocalityCompare);
|
|
|
+}
|
|
|
+ /*}}}*/
|
|
|
+// Search - Perform a search /*{{{*/
|
|
|
+// ---------------------------------------------------------------------
|
|
|
+/* This searches the package names and package descriptions for a pattern */
|
|
|
+struct ExDescFile
|
|
|
+{
|
|
|
+ pkgCache::DescFile *Df;
|
|
|
+ pkgCache::VerIterator V;
|
|
|
+ map_id_t ID;
|
|
|
+};
|
|
|
+static bool Search(CommandLine &CmdL)
|
|
|
+{
|
|
|
+ bool const ShowFull = _config->FindB("APT::Cache::ShowFull",false);
|
|
|
+ unsigned int const NumPatterns = CmdL.FileSize() -1;
|
|
|
+
|
|
|
+ pkgCacheFile CacheFile;
|
|
|
+ pkgCache *Cache = CacheFile.GetPkgCache();
|
|
|
+ pkgDepCache::Policy *Plcy = CacheFile.GetPolicy();
|
|
|
+ if (unlikely(Cache == NULL || Plcy == NULL))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Make sure there is at least one argument
|
|
|
+ if (NumPatterns < 1)
|
|
|
+ return _error->Error(_("You must give at least one search pattern"));
|
|
|
+
|
|
|
+ // Compile the regex pattern
|
|
|
+ regex_t *Patterns = new regex_t[NumPatterns];
|
|
|
+ memset(Patterns,0,sizeof(*Patterns)*NumPatterns);
|
|
|
+ for (unsigned I = 0; I != NumPatterns; I++)
|
|
|
+ {
|
|
|
+ if (regcomp(&Patterns[I],CmdL.FileList[I+1],REG_EXTENDED | REG_ICASE |
|
|
|
+ REG_NOSUB) != 0)
|
|
|
+ {
|
|
|
+ for (; I != 0; I--)
|
|
|
+ regfree(&Patterns[I]);
|
|
|
+ return _error->Error("Regex compilation error");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_error->PendingError() == true)
|
|
|
+ {
|
|
|
+ for (unsigned I = 0; I != NumPatterns; I++)
|
|
|
+ regfree(&Patterns[I]);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ size_t const descCount = Cache->HeaderP->GroupCount + 1;
|
|
|
+ ExDescFile *DFList = new ExDescFile[descCount];
|
|
|
+ memset(DFList,0,sizeof(*DFList) * descCount);
|
|
|
+
|
|
|
+ bool *PatternMatch = new bool[descCount * NumPatterns];
|
|
|
+ memset(PatternMatch,false,sizeof(*PatternMatch) * descCount * NumPatterns);
|
|
|
+
|
|
|
+ // Map versions that we want to write out onto the VerList array.
|
|
|
+ bool const NamesOnly = _config->FindB("APT::Cache::NamesOnly",false);
|
|
|
+ for (pkgCache::GrpIterator G = Cache->GrpBegin(); G.end() == false; ++G)
|
|
|
+ {
|
|
|
+ size_t const PatternOffset = G->ID * NumPatterns;
|
|
|
+ size_t unmatched = 0, matched = 0;
|
|
|
+ for (unsigned I = 0; I < NumPatterns; ++I)
|
|
|
+ {
|
|
|
+ if (PatternMatch[PatternOffset + I] == true)
|
|
|
+ ++matched;
|
|
|
+ else if (regexec(&Patterns[I],G.Name(),0,0,0) == 0)
|
|
|
+ PatternMatch[PatternOffset + I] = true;
|
|
|
+ else
|
|
|
+ ++unmatched;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 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)
|
|
|
+ {
|
|
|
+ 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].V = V;
|
|
|
+ DFList[G->ID].ID = G->ID;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (unmatched == NumPatterns)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ // Include all the packages that provide matching names too
|
|
|
+ for (pkgCache::PrvIterator Prv = P.ProvidesList() ; Prv.end() == false; ++Prv)
|
|
|
+ {
|
|
|
+ pkgCache::VerIterator V = Plcy->GetCandidateVer(Prv.OwnerPkg());
|
|
|
+ if (V.end() == true)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ unsigned long id = Prv.OwnerPkg().Group()->ID;
|
|
|
+ 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].V = V;
|
|
|
+ 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)
|
|
|
+ {
|
|
|
+ pkgRecords::Parser &P = Recs.Lookup(pkgCache::DescFileIterator(*Cache,J->Df));
|
|
|
+ size_t const PatternOffset = J->ID * NumPatterns;
|
|
|
+
|
|
|
+ if (NamesOnly == false)
|
|
|
+ {
|
|
|
+ std::string const LongDesc = P.LongDesc();
|
|
|
+ for (unsigned I = 0; I < NumPatterns; ++I)
|
|
|
+ {
|
|
|
+ if (PatternMatch[PatternOffset + I] == true)
|
|
|
+ continue;
|
|
|
+ else if (regexec(&Patterns[I],LongDesc.c_str(),0,0,0) == 0)
|
|
|
+ PatternMatch[PatternOffset + I] = 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)
|
|
|
+ DisplayRecordV1(CacheFile, J->V, std::cout);
|
|
|
+ else
|
|
|
+ printf("%s - %s\n",P.Name().c_str(),P.ShortDesc().c_str());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ delete [] DFList;
|
|
|
+ delete [] PatternMatch;
|
|
|
+ for (unsigned I = 0; I != NumPatterns; I++)
|
|
|
+ regfree(&Patterns[I]);
|
|
|
+ delete [] Patterns;
|
|
|
+ if (ferror(stdout))
|
|
|
+ return _error->Error("Write to stdout failed");
|
|
|
+ return true;
|
|
|
+}
|
|
|
+ /*}}}*/
|
|
|
+bool DoSearch(CommandLine &CmdL) /*{{{*/
|
|
|
+{
|
|
|
+ int const ShowVersion = _config->FindI("APT::Cache::Search::Version", 1);
|
|
|
+ if (ShowVersion <= 1)
|
|
|
+ return Search(CmdL);
|
|
|
+ return FullTextSearch(CmdL);
|
|
|
+}
|
|
|
+
|