apt  2.2.4
About: Apt (Advanced Package Tool) is a management system for software packages (Debian/Ubuntu). Release series 2.2.
  Fossies Dox: apt-2.2.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

private-search.cc
Go to the documentation of this file.
1 // Includes /*{{{*/
2 #include <config.h>
3 
5 #include <apt-pkg/cachefile.h>
6 #include <apt-pkg/cacheset.h>
7 #include <apt-pkg/cmndline.h>
8 #include <apt-pkg/configuration.h>
9 #include <apt-pkg/depcache.h>
10 #include <apt-pkg/macros.h>
11 #include <apt-pkg/pkgcache.h>
12 #include <apt-pkg/pkgrecords.h>
13 #include <apt-pkg/policy.h>
14 #include <apt-pkg/progress.h>
15 
22 
23 #include <iostream>
24 #include <map>
25 #include <sstream>
26 #include <string>
27 #include <utility>
28 #include <vector>
29 #include <string.h>
30 
31 #include <apti18n.h>
32  /*}}}*/
33 
34 static std::vector<pkgCache::DescIterator> const TranslatedDescriptionsList(pkgCache::VerIterator const &V) /*{{{*/
35 {
36  std::vector<pkgCache::DescIterator> Descriptions;
37 
38  for (std::string const &lang: APT::Configuration::getLanguages())
39  {
40  pkgCache::DescIterator Desc = V.TranslatedDescriptionForLanguage(lang);
41  if (Desc.IsGood())
42  Descriptions.push_back(Desc);
43  }
44 
45  if (Descriptions.empty() && V.TranslatedDescription().IsGood())
46  Descriptions.push_back(V.TranslatedDescription());
47 
48  return Descriptions;
49 }
50 
51  /*}}}*/
52 static bool FullTextSearch(CommandLine &CmdL) /*{{{*/
53 {
54 
57  pkgCache *Cache = CacheFile.GetPkgCache();
59  if (unlikely(Cache == NULL || Plcy == NULL))
60  return false;
61 
62  // Make sure there is at least one argument
63  unsigned int const NumPatterns = CmdL.FileSize() -1;
64  if (NumPatterns < 1)
65  return _error->Error(_("You must give at least one search pattern"));
66 
67  RunJsonHook("AptCli::Hooks::Search", "org.debian.apt.hooks.search.pre", CmdL.FileList, CacheFile);
68 
69 #define APT_FREE_PATTERNS() for (std::vector<regex_t>::iterator P = Patterns.begin(); \
70  P != Patterns.end(); ++P) { regfree(&(*P)); }
71 
72  // Compile the regex pattern
73  std::vector<regex_t> Patterns;
74  for (unsigned int I = 0; I != NumPatterns; ++I)
75  {
76  regex_t pattern;
77  if (regcomp(&pattern, CmdL.FileList[I + 1], REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0)
78  {
80  return _error->Error("Regex compilation error");
81  }
82  Patterns.push_back(pattern);
83  }
84 
85  std::map<std::string, std::string> output_map;
86 
88  OpTextProgress progress(*_config);
89  progress.OverallProgress(0, 100, 50, _("Sorting"));
90  GetLocalitySortedVersionSet(CacheFile, &bag, &progress);
92 
93  progress.OverallProgress(50, 100, 50, _("Full Text Search"));
94  progress.SubProgress(bag.size());
95  pkgRecords records(CacheFile);
96 
97  std::string format = "${color:highlight}${Package}${color:neutral}/${Origin} ${Version} ${Architecture}${ }${apt:Status}\n";
98  if (_config->FindB("APT::Cache::ShowFull",false) == false)
99  format += " ${Description}\n";
100  else
101  format += " ${LongDescription}\n";
102 
103  bool const NamesOnly = _config->FindB("APT::Cache::NamesOnly", false);
104  int Done = 0;
105  std::vector<bool> PkgsDone(Cache->Head().PackageCount, false);
106  for ( ;V != bag.end(); ++V)
107  {
108  if (Done%500 == 0)
109  progress.Progress(Done);
110  ++Done;
111 
112  // we want to list each package only once
113  pkgCache::PkgIterator const P = V.ParentPkg();
114  if (PkgsDone[P->ID] == true)
115  continue;
116 
117  std::vector<std::string> PkgDescriptions;
118  if (not NamesOnly)
119  {
120  for (auto &Desc: TranslatedDescriptionsList(V))
121  {
122  pkgRecords::Parser &parser = records.Lookup(Desc.FileList());
123  PkgDescriptions.push_back(parser.LongDesc());
124  }
125  }
126 
127  bool all_found = true;
128 
129  char const * const PkgName = P.Name();
130  std::vector<bool> SkipDescription(PkgDescriptions.size(), false);
131  for (std::vector<regex_t>::const_iterator pattern = Patterns.begin();
132  pattern != Patterns.end(); ++pattern)
133  {
134  if (regexec(&(*pattern), PkgName, 0, 0, 0) == 0)
135  continue;
136  else if (not NamesOnly)
137  {
138  bool found = false;
139 
140  for (std::vector<std::string>::size_type i = 0; i < PkgDescriptions.size(); ++i)
141  {
142  if (not SkipDescription[i])
143  {
144  if (regexec(&(*pattern), PkgDescriptions[i].c_str(), 0, 0, 0) == 0)
145  found = true;
146  else
147  SkipDescription[i] = true;
148  }
149  }
150 
151  if (found)
152  continue;
153  }
154 
155  // search patterns are AND, so one failing fails all
156  all_found = false;
157  break;
158  }
159 
160  if (all_found == true)
161  {
162  PkgsDone[P->ID] = true;
163  std::stringstream outs;
164  ListSingleVersion(CacheFile, records, V, outs, format);
165  output_map.insert(std::make_pair<std::string, std::string>(
166  PkgName, outs.str()));
167  }
168  }
170  progress.Done();
171 
172  // FIXME: SORT! and make sorting flexible (alphabetic, by pkg status)
173  // output the sorted map
174  std::map<std::string, std::string>::const_iterator K;
175  for (K = output_map.begin(); K != output_map.end(); ++K)
176  std::cout << (*K).second << std::endl;
177 
178  if (output_map.empty())
179  RunJsonHook("AptCli::Hooks::Search", "org.debian.apt.hooks.search.fail", CmdL.FileList, CacheFile);
180  else
181  RunJsonHook("AptCli::Hooks::Search", "org.debian.apt.hooks.search.post", CmdL.FileList, CacheFile);
182  return true;
183 }
184  /*}}}*/
185 // LocalitySort - Sort a version list by package file locality /*{{{*/
186 static int LocalityCompare(const void * const a, const void * const b)
187 {
188  pkgCache::VerFile const * const A = *static_cast<pkgCache::VerFile const * const *>(a);
189  pkgCache::VerFile const * const B = *static_cast<pkgCache::VerFile const * const *>(b);
190 
191  if (A == 0 && B == 0)
192  return 0;
193  if (A == 0)
194  return 1;
195  if (B == 0)
196  return -1;
197 
198  if (A->File == B->File)
199  return A->Offset - B->Offset;
200  return A->File - B->File;
201 }
202 void LocalitySort(pkgCache::VerFile ** const begin, unsigned long long const Count,size_t const Size)
203 {
204  qsort(begin,Count,Size,LocalityCompare);
205 }
206 static void LocalitySort(pkgCache::DescFile ** const begin, unsigned long long const Count,size_t const Size)
207 {
208  qsort(begin,Count,Size,LocalityCompare);
209 }
210  /*}}}*/
211 // Search - Perform a search /*{{{*/
212 // ---------------------------------------------------------------------
213 /* This searches the package names and package descriptions for a pattern */
215 {
219  ExDescFile() : Df(nullptr), ID(0) {}
220 };
221 static bool Search(CommandLine &CmdL)
222 {
223  bool const ShowFull = _config->FindB("APT::Cache::ShowFull",false);
224  unsigned int const NumPatterns = CmdL.FileSize() -1;
225 
227  pkgCache *Cache = CacheFile.GetPkgCache();
229  if (unlikely(Cache == NULL || Plcy == NULL))
230  return false;
231 
232  // Make sure there is at least one argument
233  if (NumPatterns < 1)
234  return _error->Error(_("You must give at least one search pattern"));
235 
236  // Compile the regex pattern
237  regex_t *Patterns = new regex_t[NumPatterns];
238  memset(Patterns,0,sizeof(*Patterns)*NumPatterns);
239  for (unsigned I = 0; I != NumPatterns; I++)
240  {
241  if (regcomp(&Patterns[I],CmdL.FileList[I+1],REG_EXTENDED | REG_ICASE |
242  REG_NOSUB) != 0)
243  {
244  for (; I != 0; I--)
245  regfree(&Patterns[I]);
246  return _error->Error("Regex compilation error");
247  }
248  }
249 
250  if (_error->PendingError() == true)
251  {
252  for (unsigned I = 0; I != NumPatterns; I++)
253  regfree(&Patterns[I]);
254  return false;
255  }
256 
257  size_t const descCount = Cache->HeaderP->GroupCount + 1;
258  ExDescFile *DFList = new ExDescFile[descCount];
259 
260  bool *PatternMatch = new bool[descCount * NumPatterns];
261  memset(PatternMatch,false,sizeof(*PatternMatch) * descCount * NumPatterns);
262 
263  // Map versions that we want to write out onto the VerList array.
264  bool const NamesOnly = _config->FindB("APT::Cache::NamesOnly",false);
265  for (pkgCache::GrpIterator G = Cache->GrpBegin(); G.end() == false; ++G)
266  {
267  size_t const PatternOffset = G->ID * NumPatterns;
268  size_t unmatched = 0, matched = 0;
269  for (unsigned I = 0; I < NumPatterns; ++I)
270  {
271  if (PatternMatch[PatternOffset + I] == true)
272  ++matched;
273  else if (regexec(&Patterns[I],G.Name(),0,0,0) == 0)
274  PatternMatch[PatternOffset + I] = true;
275  else
276  ++unmatched;
277  }
278 
279  // already dealt with this package?
280  if (matched == NumPatterns)
281  continue;
282 
283  // Doing names only, drop any that don't match..
284  if (NamesOnly == true && unmatched == NumPatterns)
285  continue;
286 
287  // Find the proper version to use
288  pkgCache::PkgIterator P = G.FindPreferredPkg();
289  if (P.end() == true)
290  continue;
292  if (V.end() == false)
293  {
294  pkgCache::DescIterator const D = V.TranslatedDescription();
295  //FIXME: packages without a description can't be found
296  if (D.end() == true)
297  continue;
298  DFList[G->ID].Df = D.FileList();
299  DFList[G->ID].V = V;
300  DFList[G->ID].ID = G->ID;
301  }
302 
303  if (unmatched == NumPatterns)
304  continue;
305 
306  // Include all the packages that provide matching names too
307  for (pkgCache::PrvIterator Prv = P.ProvidesList() ; Prv.end() == false; ++Prv)
308  {
309  pkgCache::VerIterator V = Plcy->GetCandidateVer(Prv.OwnerPkg());
310  if (V.end() == true)
311  continue;
312 
313  unsigned long id = Prv.OwnerPkg().Group()->ID;
314  pkgCache::DescIterator const D = V.TranslatedDescription();
315  //FIXME: packages without a description can't be found
316  if (D.end() == true)
317  continue;
318  DFList[id].Df = D.FileList();
319  DFList[id].V = V;
320  DFList[id].ID = id;
321 
322  size_t const PrvPatternOffset = id * NumPatterns;
323  for (unsigned I = 0; I < NumPatterns; ++I)
324  PatternMatch[PrvPatternOffset + I] |= PatternMatch[PatternOffset + I];
325  }
326  }
327 
328  LocalitySort(&DFList->Df, Cache->HeaderP->GroupCount, sizeof(*DFList));
329 
330  // Create the text record parser
331  pkgRecords Recs(*Cache);
332  // Iterate over all the version records and check them
333  for (ExDescFile *J = DFList; J->Df != 0; ++J)
334  {
335  size_t const PatternOffset = J->ID * NumPatterns;
336  if (not NamesOnly)
337  {
338  std::vector<std::string> PkgDescriptions;
339  for (auto &Desc: TranslatedDescriptionsList(J->V))
340  {
341  pkgRecords::Parser &parser = Recs.Lookup(Desc.FileList());
342  PkgDescriptions.push_back(parser.LongDesc());
343  }
344 
345  std::vector<bool> SkipDescription(PkgDescriptions.size(), false);
346  for (unsigned I = 0; I < NumPatterns; ++I)
347  {
348  if (PatternMatch[PatternOffset + I])
349  continue;
350  else
351  {
352  bool found = false;
353 
354  for (std::vector<std::string>::size_type k = 0; k < PkgDescriptions.size(); ++k)
355  {
356  if (not SkipDescription[k])
357  {
358  if (regexec(&Patterns[I], PkgDescriptions[k].c_str(), 0, 0, 0) == 0)
359  {
360  found = true;
361  PatternMatch[PatternOffset + I] = true;
362  }
363  else
364  SkipDescription[k] = true;
365  }
366  }
367 
368  if (not found)
369  break;
370  }
371  }
372  }
373 
374  bool matchedAll = true;
375  for (unsigned I = 0; I < NumPatterns; ++I)
376  if (PatternMatch[PatternOffset + I] == false)
377  {
378  matchedAll = false;
379  break;
380  }
381 
382  if (matchedAll == true)
383  {
384  if (ShowFull == true)
385  {
387  auto &Parser = LookupParser(Recs, J->V, Vf);
388  char const *Start, *Stop;
389  Parser.GetRec(Start, Stop);
390  size_t const Length = Stop - Start;
391  DisplayRecordV1(CacheFile, Recs, J->V, Vf, Start, Length, std::cout);
392  }
393  else
394  {
395  pkgRecords::Parser &P = Recs.Lookup(pkgCache::DescFileIterator(*Cache, J->Df));
396  printf("%s - %s\n", P.Name().c_str(), P.ShortDesc().c_str());
397  }
398  }
399  }
400 
401  delete [] DFList;
402  delete [] PatternMatch;
403  for (unsigned I = 0; I != NumPatterns; I++)
404  regfree(&Patterns[I]);
405  delete [] Patterns;
406  if (ferror(stdout))
407  return _error->Error("Write to stdout failed");
408  return true;
409 }
410  /*}}}*/
411 bool DoSearch(CommandLine &CmdL) /*{{{*/
412 {
413  int const ShowVersion = _config->FindI("APT::Cache::Search::Version", 1);
414  if (ShowVersion <= 1)
415  return Search(CmdL);
416  return FullTextSearch(CmdL);
417 }
418 
static bool std::string const metaIndex const *const pkgAcqMetaClearSig *const pkgAcquire::Item *const I
size_t size() const APT_OVERRIDE
Definition: cacheset.h:817
const_iterator begin() const
Definition: cacheset.h:825
const_iterator end() const
Definition: cacheset.h:826
const char ** FileList
Definition: cmndline.h:78
unsigned int FileSize() const APT_PURE
Definition: cmndline.cc:353
int FindI(const char *Name, int const &Default=0) const
bool FindB(const char *Name, bool const &Default=false) const
void OverallProgress(unsigned long long Current, unsigned long long Total, unsigned long long Size, const std::string &Op)
Definition: progress.cc:55
void Progress(unsigned long long Current)
Definition: progress.cc:43
void SubProgress(unsigned long long SubTotal, const std::string &Op="", float const Percent=-1)
Definition: progress.cc:73
virtual void Done() APT_OVERRIDE
Definition: progress.cc:152
pkgPolicy * GetPolicy()
Definition: cachefile.h:75
pkgDepCache * GetDepCache()
Definition: cachefile.h:74
pkgCache * GetPkgCache()
Definition: cachefile.h:73
virtual VerIterator GetCandidateVer(PkgIterator const &Pkg)
Definition: depcache.cc:2109
Parser & Lookup(pkgCache::VerFileIterator const &Ver)
Definition: pkgrecords.cc:62
Configuration * _config
APT_PUBLIC std::vector< std::string > const getLanguages(bool const &All=false, bool const &Cached=true, char const **const Locale=0)
Returns a vector of Language Codes.
pkgCache - Structure definitions for the cache file
uint32_t map_id_t
Definition: pkgcache.h:93
bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, APT::VersionContainerInterface *const vci, OpProgress *const progress)
bool RunJsonHook(std::string const &option, std::string const &method, const char **FileList, CacheFile &Cache, std::set< std::string > const &UnknownPackages)
Run the Json hook processes in the given option.
void ListSingleVersion(pkgCacheFile &CacheFile, pkgRecords &records, pkgCache::VerIterator const &V, std::ostream &out, std::string const &format)
static int LocalityCompare(const void *const a, const void *const b)
static std::vector< pkgCache::DescIterator > const TranslatedDescriptionsList(pkgCache::VerIterator const &V)
static bool Search(CommandLine &CmdL)
static bool FullTextSearch(CommandLine &CmdL)
bool DoSearch(CommandLine &CmdL)
#define APT_FREE_PATTERNS()
void LocalitySort(pkgCache::VerFile **const begin, unsigned long long const Count, size_t const Size)
bool DisplayRecordV1(pkgCacheFile &, pkgRecords &Recs, pkgCache::VerIterator const &V, pkgCache::VerFileIterator const &Vf, char const *Buffer, size_t Length, std::ostream &out)
Definition: private-show.cc:99
pkgRecords::Parser & LookupParser(pkgRecords &Recs, pkgCache::VerIterator const &V, pkgCache::VerFileIterator &Vf)
Definition: private-show.cc:35
pkgCache::VerIterator V
pkgCache::DescFile * Df
string Name
Definition: apt-sortpkgs.cc:43
associates a description with a Translation file
Definition: pkgcache.h:607
associates a version with a PackageFile
Definition: pkgcache.h:593
map_filesize_t Offset
position in the package file
Definition: pkgcache.h:599
map_pointer< PackageFile > File
index of the package file that this version was found in
Definition: pkgcache.h:595