4 #include <apt-pkg/cachefile.h>
5 #include <apt-pkg/cacheset.h>
6 #include <apt-pkg/cmndline.h>
7 #include <apt-pkg/pkgrecords.h>
8 #include <apt-pkg/policy.h>
9 #include <apt-pkg/progress.h>
10 #include <apt-pkg/cacheiterators.h>
11 #include <apt-pkg/configuration.h>
12 #include <apt-pkg/depcache.h>
13 #include <apt-pkg/macros.h>
14 #include <apt-pkg/pkgcache.h>
16 #include <apt-private/private-cacheset.h>
17 #include <apt-private/private-output.h>
18 #include <apt-private/private-search.h>
19 #include <apt-private/private-show.h>
31 static bool FullTextSearch(CommandLine
&CmdL
) /*{{{*/
33 pkgCacheFile CacheFile
;
34 pkgCache
*Cache
= CacheFile
.GetPkgCache();
35 pkgDepCache::Policy
*Plcy
= CacheFile
.GetPolicy();
36 if (unlikely(Cache
== NULL
|| Plcy
== NULL
))
39 // Make sure there is at least one argument
40 unsigned int const NumPatterns
= CmdL
.FileSize() -1;
42 return _error
->Error(_("You must give at least one search pattern"));
44 #define APT_FREE_PATTERNS() for (std::vector<regex_t>::iterator P = Patterns.begin(); \
45 P != Patterns.end(); ++P) { regfree(&(*P)); }
47 // Compile the regex pattern
48 std::vector
<regex_t
> Patterns
;
49 for (unsigned int I
= 0; I
!= NumPatterns
; ++I
)
52 if (regcomp(&pattern
, CmdL
.FileList
[I
+ 1], REG_EXTENDED
| REG_ICASE
| REG_NOSUB
) != 0)
55 return _error
->Error("Regex compilation error");
57 Patterns
.push_back(pattern
);
60 std::map
<std::string
, std::string
> output_map
;
62 LocalitySortedVersionSet bag
;
63 OpTextProgress
progress(*_config
);
64 progress
.OverallProgress(0, 100, 50, _("Sorting"));
65 GetLocalitySortedVersionSet(CacheFile
, &bag
, &progress
);
66 LocalitySortedVersionSet::iterator V
= bag
.begin();
68 progress
.OverallProgress(50, 100, 50, _("Full Text Search"));
69 progress
.SubProgress(bag
.size());
70 pkgRecords
records(CacheFile
);
72 std::string format
= "${color:highlight}${Package}${color:neutral}/${Origin} ${Version} ${Architecture}${ }${apt:Status}\n";
73 if (_config
->FindB("APT::Cache::ShowFull",false) == false)
74 format
+= " ${Description}\n";
76 format
+= " ${LongDescription}\n";
78 bool const NamesOnly
= _config
->FindB("APT::Cache::NamesOnly", false);
80 std::vector
<bool> PkgsDone(Cache
->Head().PackageCount
, false);
81 for ( ;V
!= bag
.end(); ++V
)
84 progress
.Progress(Done
);
87 // we want to list each package only once
88 pkgCache::PkgIterator
const P
= V
.ParentPkg();
89 if (PkgsDone
[P
->ID
] == true)
92 char const * const PkgName
= P
.Name();
93 pkgCache::DescIterator Desc
= V
.TranslatedDescription();
94 std::string LongDesc
= "";
95 if (Desc
.end() == false)
97 pkgRecords::Parser
&parser
= records
.Lookup(Desc
.FileList());
98 LongDesc
= parser
.LongDesc();
101 bool all_found
= true;
102 for (std::vector
<regex_t
>::const_iterator pattern
= Patterns
.begin();
103 pattern
!= Patterns
.end(); ++pattern
)
105 if (regexec(&(*pattern
), PkgName
, 0, 0, 0) == 0)
107 else if (NamesOnly
== false && regexec(&(*pattern
), LongDesc
.c_str(), 0, 0, 0) == 0)
109 // search patterns are AND, so one failing fails all
113 if (all_found
== true)
115 PkgsDone
[P
->ID
] = true;
116 std::stringstream outs
;
117 ListSingleVersion(CacheFile
, records
, V
, outs
, format
);
118 output_map
.insert(std::make_pair
<std::string
, std::string
>(
119 PkgName
, outs
.str()));
125 // FIXME: SORT! and make sorting flexible (alphabetic, by pkg status)
126 // output the sorted map
127 std::map
<std::string
, std::string
>::const_iterator K
;
128 for (K
= output_map
.begin(); K
!= output_map
.end(); ++K
)
129 std::cout
<< (*K
).second
<< std::endl
;
134 // LocalitySort - Sort a version list by package file locality /*{{{*/
135 static int LocalityCompare(const void * const a
, const void * const b
)
137 pkgCache::VerFile
const * const A
= *(pkgCache::VerFile
const * const * const)a
;
138 pkgCache::VerFile
const * const B
= *(pkgCache::VerFile
const * const * const)b
;
140 if (A
== 0 && B
== 0)
147 if (A
->File
== B
->File
)
148 return A
->Offset
- B
->Offset
;
149 return A
->File
- B
->File
;
151 void LocalitySort(pkgCache::VerFile
** const begin
, unsigned long long const Count
,size_t const Size
)
153 qsort(begin
,Count
,Size
,LocalityCompare
);
155 static void LocalitySort(pkgCache::DescFile
** const begin
, unsigned long long const Count
,size_t const Size
)
157 qsort(begin
,Count
,Size
,LocalityCompare
);
160 // Search - Perform a search /*{{{*/
161 // ---------------------------------------------------------------------
162 /* This searches the package names and package descriptions for a pattern */
165 pkgCache::DescFile
*Df
;
166 pkgCache::VerIterator V
;
169 static bool Search(CommandLine
&CmdL
)
171 bool const ShowFull
= _config
->FindB("APT::Cache::ShowFull",false);
172 unsigned int const NumPatterns
= CmdL
.FileSize() -1;
174 pkgCacheFile CacheFile
;
175 pkgCache
*Cache
= CacheFile
.GetPkgCache();
176 pkgDepCache::Policy
*Plcy
= CacheFile
.GetPolicy();
177 if (unlikely(Cache
== NULL
|| Plcy
== NULL
))
180 // Make sure there is at least one argument
182 return _error
->Error(_("You must give at least one search pattern"));
184 // Compile the regex pattern
185 regex_t
*Patterns
= new regex_t
[NumPatterns
];
186 memset(Patterns
,0,sizeof(*Patterns
)*NumPatterns
);
187 for (unsigned I
= 0; I
!= NumPatterns
; I
++)
189 if (regcomp(&Patterns
[I
],CmdL
.FileList
[I
+1],REG_EXTENDED
| REG_ICASE
|
193 regfree(&Patterns
[I
]);
194 return _error
->Error("Regex compilation error");
198 if (_error
->PendingError() == true)
200 for (unsigned I
= 0; I
!= NumPatterns
; I
++)
201 regfree(&Patterns
[I
]);
205 size_t const descCount
= Cache
->HeaderP
->GroupCount
+ 1;
206 ExDescFile
*DFList
= new ExDescFile
[descCount
];
207 memset(DFList
,0,sizeof(*DFList
) * descCount
);
209 bool *PatternMatch
= new bool[descCount
* NumPatterns
];
210 memset(PatternMatch
,false,sizeof(*PatternMatch
) * descCount
* NumPatterns
);
212 // Map versions that we want to write out onto the VerList array.
213 bool const NamesOnly
= _config
->FindB("APT::Cache::NamesOnly",false);
214 for (pkgCache::GrpIterator G
= Cache
->GrpBegin(); G
.end() == false; ++G
)
216 size_t const PatternOffset
= G
->ID
* NumPatterns
;
217 size_t unmatched
= 0, matched
= 0;
218 for (unsigned I
= 0; I
< NumPatterns
; ++I
)
220 if (PatternMatch
[PatternOffset
+ I
] == true)
222 else if (regexec(&Patterns
[I
],G
.Name(),0,0,0) == 0)
223 PatternMatch
[PatternOffset
+ I
] = true;
228 // already dealt with this package?
229 if (matched
== NumPatterns
)
232 // Doing names only, drop any that don't match..
233 if (NamesOnly
== true && unmatched
== NumPatterns
)
236 // Find the proper version to use
237 pkgCache::PkgIterator P
= G
.FindPreferredPkg();
240 pkgCache::VerIterator V
= Plcy
->GetCandidateVer(P
);
241 if (V
.end() == false)
243 pkgCache::DescIterator
const D
= V
.TranslatedDescription();
244 //FIXME: packages without a description can't be found
247 DFList
[G
->ID
].Df
= D
.FileList();
249 DFList
[G
->ID
].ID
= G
->ID
;
252 if (unmatched
== NumPatterns
)
255 // Include all the packages that provide matching names too
256 for (pkgCache::PrvIterator Prv
= P
.ProvidesList() ; Prv
.end() == false; ++Prv
)
258 pkgCache::VerIterator V
= Plcy
->GetCandidateVer(Prv
.OwnerPkg());
262 unsigned long id
= Prv
.OwnerPkg().Group()->ID
;
263 pkgCache::DescIterator
const D
= V
.TranslatedDescription();
264 //FIXME: packages without a description can't be found
267 DFList
[id
].Df
= D
.FileList();
271 size_t const PrvPatternOffset
= id
* NumPatterns
;
272 for (unsigned I
= 0; I
< NumPatterns
; ++I
)
273 PatternMatch
[PrvPatternOffset
+ I
] |= PatternMatch
[PatternOffset
+ I
];
277 LocalitySort(&DFList
->Df
, Cache
->HeaderP
->GroupCount
, sizeof(*DFList
));
279 // Create the text record parser
280 pkgRecords
Recs(*Cache
);
281 // Iterate over all the version records and check them
282 for (ExDescFile
*J
= DFList
; J
->Df
!= 0; ++J
)
284 pkgRecords::Parser
&P
= Recs
.Lookup(pkgCache::DescFileIterator(*Cache
,J
->Df
));
285 size_t const PatternOffset
= J
->ID
* NumPatterns
;
287 if (NamesOnly
== false)
289 std::string
const LongDesc
= P
.LongDesc();
290 for (unsigned I
= 0; I
< NumPatterns
; ++I
)
292 if (PatternMatch
[PatternOffset
+ I
] == true)
294 else if (regexec(&Patterns
[I
],LongDesc
.c_str(),0,0,0) == 0)
295 PatternMatch
[PatternOffset
+ I
] = true;
299 bool matchedAll
= true;
300 for (unsigned I
= 0; I
< NumPatterns
; ++I
)
301 if (PatternMatch
[PatternOffset
+ I
] == false)
307 if (matchedAll
== true)
309 if (ShowFull
== true)
310 DisplayRecordV1(CacheFile
, J
->V
, std::cout
);
312 printf("%s - %s\n",P
.Name().c_str(),P
.ShortDesc().c_str());
317 delete [] PatternMatch
;
318 for (unsigned I
= 0; I
!= NumPatterns
; I
++)
319 regfree(&Patterns
[I
]);
322 return _error
->Error("Write to stdout failed");
326 bool DoSearch(CommandLine
&CmdL
) /*{{{*/
328 int const ShowVersion
= _config
->FindI("APT::Cache::Search::Version", 1);
329 if (ShowVersion
<= 1)
331 return FullTextSearch(CmdL
);