1 : // -*- C++ -*-
2 :
3 : #include <ept/core/apt/recordparser.h>
4 :
5 : #ifndef EPT_APT_RECORD_H
6 : #define EPT_APT_RECORD_H
7 :
8 : namespace ept {
9 : namespace core {
10 : namespace record {
11 :
12 : struct Source;
13 :
14 : struct InternalList {
15 : Source *m_source;
16 : size_t m_idx;
17 :
18 : Internal head();
19 : const Internal head() const;
20 : bool empty() const;
21 :
22 870 : InternalList tail() const {
23 870 : InternalList t = *this;
24 870 : ++ t.m_idx;
25 : return t;
26 : }
27 :
28 2 : InternalList( Source &s )
29 2 : : m_source( &s ), m_idx( 0 )
30 2 : {}
31 : };
32 :
33 : struct Setup {
34 : typedef ept::Token Token;
35 : typedef record::Internal Internal;
36 : typedef record::PropertyId PropertyId;
37 : typedef record::InternalList InternalList;
38 : };
39 :
40 : template<> struct PropertyType< InstalledSize > { typedef int T; };
41 : template<> struct PropertyType< PackageSize > { typedef int T; };
42 :
43 : struct Parser: RecordParser
44 1310 : {
45 : bool parseBool(bool& def, const std::string& str) const
46 : {
47 : // Believe it or not, this is what apt does to interpret bool fields
48 : if (str == "no" || str == "false" || str == "without" ||
49 : str == "off" || str == "disable")
50 : return false;
51 :
52 : if (str == "yes" || str == "true" || str == "with" ||
53 : str == "on" || str == "enable")
54 : return true;
55 :
56 : return def;
57 : }
58 :
59 : public:
60 : Parser() : RecordParser() {}
61 1310 : Parser(const std::string& str) : RecordParser(str) {}
62 :
63 : template< PropertyId p >
64 : typename PropertyType< p >::T parse( typename PropertyType< p >::T def,
65 : std::string data );
66 :
67 : template< typename T >
68 : struct Default {
69 : static T def;
70 : };
71 :
72 : template< typename T > T parse( const T &def,
73 : const std::string &field ) const;
74 :
75 : template< PropertyId p >
76 : typename PropertyType< p >::T get(
77 : const typename PropertyType< p >::T &def
78 1308 : = Default< typename PropertyType< p >::T >::def ) const
79 : {
80 : return parse< typename PropertyType< p >::T >( def,
81 1308 : lookup( fields[ p ] ) );
82 : }
83 :
84 : };
85 :
86 25 : template< typename T > T Parser::Default< T >::def = T();
87 :
88 : template<> inline std::string Parser::get< ShortDescription >(
89 2 : const std::string& def ) const
90 : {
91 2 : std::string str = lookup( fields[ Description ] );
92 4 : if (str == std::string())
93 1 : return def;
94 1 : size_t pos = str.find("\n");
95 1 : if (pos == std::string::npos)
96 0 : return str;
97 : else
98 1 : return str.substr(0, pos);
99 : }
100 :
101 : template<> inline std::string Parser::get< LongDescription >(
102 : const std::string& def ) const
103 : {
104 : std::string str = lookup( fields[ Description ] );
105 : if (str == std::string())
106 : return def;
107 : size_t pos = str.find("\n");
108 : if (pos == std::string::npos)
109 : return str;
110 : else
111 : {
112 : // Trim trailing spaces
113 : for (++pos; pos < str.size() && isspace(str[pos]); ++pos)
114 : ;
115 : return str.substr(pos);
116 : }
117 : }
118 :
119 : template<> inline std::string Parser::parse< std::string >(
120 1307 : const std::string& def, const std::string& str) const
121 : {
122 1307 : if (str == std::string())
123 0 : return def;
124 1307 : return str;
125 : }
126 :
127 : template<> inline int Parser::parse< int >(
128 1 : const int& def, const std::string& str) const
129 : {
130 1 : if (str == string())
131 0 : return def;
132 1 : return (size_t)strtoul(str.c_str(), NULL, 10);
133 : }
134 :
135 : struct Source : core::Source< Source, Setup, PropertyType >
136 6 : {
137 : AptDatabase &m_db;
138 :
139 : /* caching */
140 : pkgCache::PkgFileIterator lastFile;
141 : FileFd file;
142 : size_t lastOffset;
143 :
144 : /* in-order retrieval of records, for InternalList */
145 : typedef vector< pkgCache::VerFile * > VfList;
146 : VfList m_vflist;
147 :
148 1742 : VfList &vfList() {
149 1742 : if ( m_vflist.size() > 0 )
150 1741 : return m_vflist;
151 :
152 1 : m_vflist.reserve(m_db.cache().HeaderP->PackageCount + 1);
153 :
154 : // Populate the vector of versions to print
155 3778 : for (pkgCache::PkgIterator pi = m_db.cache().PkgBegin(); !pi.end(); ++pi)
156 : {
157 3777 : if (pi->VersionList == 0)
158 1989 : continue;
159 :
160 3596 : for( pkgCache::VerIterator vi = pi.VersionList(); !vi.end(); ++vi ) {
161 :
162 : // Choose a valid file that contains the record for this version
163 1808 : pkgCache::VerFileIterator vfi = vi.FileList();
164 3181 : for ( ; !vfi.end(); ++vfi )
165 1808 : if ((vfi.File()->Flags & pkgCache::Flag::NotSource) == 0)
166 435 : break;
167 :
168 1808 : if ( !vfi.end() )
169 435 : m_vflist.push_back( vfi );
170 : }
171 : }
172 :
173 1 : sort(m_vflist.begin(), m_vflist.end(), localityCompare);
174 1 : return m_vflist;
175 : }
176 :
177 6 : Source( AptDatabase &db ) : m_db( db ) {}
178 :
179 2 : InternalList listInternal() {
180 2 : return InternalList( *this );
181 : }
182 :
183 5 : Internal lookupToken( Token t ) {
184 5 : return m_db.lookupVersionFile( m_db.lookupVersion( t ) );
185 : }
186 :
187 : // Sort a version list by package file locality
188 : static bool localityCompare(const pkgCache::VerFile* a,
189 4371 : const pkgCache::VerFile* b)
190 : {
191 4371 : if (a == 0 && b == 0)
192 0 : return false;
193 4371 : if (a == 0)
194 0 : return true;
195 4371 : if (b == 0)
196 0 : return false;
197 :
198 4371 : if (a->File == b->File)
199 4371 : return a->Offset < b->Offset;
200 0 : return a->File < b->File;
201 : }
202 :
203 : void invalidate() {
204 : core::Source< Source, Setup, PropertyType >::invalidate();
205 : lastFile = pkgCache::PkgFileIterator();
206 : }
207 :
208 1311 : std::string getRecord( Internal vfi ) {
209 1311 : if ( vfi.Cache() == 0 || vfi.end() )
210 1 : return "";
211 :
212 1310 : if ((lastFile.Cache() == 0)
213 : || vfi->File + m_db.cache().PkgFileP != lastFile)
214 : {
215 : lastFile = pkgCache::PkgFileIterator(
216 5 : m_db.cache(), vfi->File + m_db.cache().PkgFileP);
217 5 : if (!lastFile.IsOk())
218 : throw wibble::exception::System(
219 : std::string("Reading the"
220 : " data record for a package from file ")
221 0 : + lastFile.FileName() );
222 5 : if (file.IsOpen())
223 0 : file.Close();
224 5 : if (!file.Open(lastFile.FileName(), FileFd::ReadOnly))
225 : throw wibble::exception::System( std::string("Opening file ")
226 0 : + lastFile.FileName() );
227 5 : lastOffset = 0;
228 : }
229 :
230 : // If we start near were we ended, avoid a seek
231 : // and enlarge the read a bit
232 1310 : size_t slack = vfi->Offset - lastOffset;
233 1310 : if ( slack > 128 ) // mornfall: was 8, making it 128
234 : {
235 871 : slack = 0;
236 871 : if ( !file.Seek( vfi->Offset ) )
237 : throw wibble::exception::System(
238 : std::string("Cannot seek to package record in file ")
239 0 : + lastFile.FileName() );
240 : }
241 :
242 1310 : char buffer[vfi->Size + slack + 1];
243 1310 : if (!file.Read(buffer, vfi->Size + slack))
244 : throw wibble::exception::System(
245 : std::string("Cannot read package "
246 0 : "record in file ") + lastFile.FileName() );
247 :
248 1310 : buffer[vfi->Size + slack] = '\0';
249 : //cerr << "Data read (slack: " << slack << ")" << endl;
250 :
251 1310 : lastOffset = vfi->Offset + vfi->Size;
252 :
253 1310 : return string(buffer+slack);
254 : }
255 :
256 435 : Token getToken( Internal i ) {
257 435 : Token t;
258 435 : t._id = getInternal< Name >( i ) + "_" + getInternal< Version >( i );
259 0 : return t;
260 : }
261 :
262 : template< PropertyId p >
263 1310 : typename PropertyType< p >::T getInternal( Internal i ) {
264 1310 : Parser rec( getRecord( i ) );
265 1310 : return rec.get< p >();
266 : }
267 : };
268 :
269 1 : template<> inline std::string Source::getInternal< Record >( Internal i ) {
270 1 : assert( !i.end() );
271 1 : return getRecord( i );
272 : }
273 :
274 870 : inline const Internal InternalList::head() const {
275 : return pkgCache::VerFileIterator( m_source->m_db.cache(),
276 870 : m_source->vfList()[ m_idx ] );
277 : }
278 :
279 872 : inline bool InternalList::empty() const {
280 872 : return m_idx == m_source->vfList().size();
281 : }
282 :
283 :
284 : }
285 : }
286 : }
287 :
288 : #endif
|