libept  0.5.25
record.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 
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 {
16  size_t m_idx;
17 
18  Internal head();
19  const Internal head() const;
20  bool empty() const;
21 
22  InternalList tail() const {
23  InternalList t = *this;
24  ++ t.m_idx;
25  return t;
26  }
27 
29  : m_source( &s ), m_idx( 0 )
30  {}
31 };
32 
33 struct Setup {
34  typedef ept::Token Token;
38 };
39 
40 template<> struct PropertyType< InstalledSize > { typedef int T; };
41 template<> struct PropertyType< PackageSize > { typedef int T; };
42 
44 {
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:
61  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
79  {
80  return parse< typename PropertyType< p >::T >( def,
81  lookup( fields[ p ] ) );
82  }
83 
84 };
85 
86 template< typename T > T Parser::Default< T >::def = T();
87 
88 template<> inline std::string Parser::get< ShortDescription >(
89  const std::string& def ) const
90 {
91  std::string str = lookup( fields[ Description ] );
92  if (str == std::string())
93  return def;
94  size_t pos = str.find("\n");
95  if (pos == std::string::npos)
96  return str;
97  else
98  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  const std::string& def, const std::string& str) const
121 {
122  if (str == std::string())
123  return def;
124  return str;
125 }
126 
127 template<> inline int Parser::parse< int >(
128  const int& def, const std::string& str) const
129 {
130  if (str == string())
131  return def;
132  return (size_t)strtoul(str.c_str(), NULL, 10);
133 }
134 
135 struct Source : core::Source< Source, Setup, PropertyType >
136 {
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;
147 
149  if ( m_vflist.size() > 0 )
150  return m_vflist;
151 
152  m_vflist.reserve(m_db.cache().HeaderP->PackageCount + 1);
153 
154  // Populate the vector of versions to print
155  for (pkgCache::PkgIterator pi = m_db.cache().PkgBegin(); !pi.end(); ++pi)
156  {
157  if (pi->VersionList == 0)
158  continue;
159 
160  for( pkgCache::VerIterator vi = pi.VersionList(); !vi.end(); ++vi ) {
161 
162  // Choose a valid file that contains the record for this version
163  pkgCache::VerFileIterator vfi = vi.FileList();
164  for ( ; !vfi.end(); ++vfi )
165  if ((vfi.File()->Flags & pkgCache::Flag::NotSource) == 0)
166  break;
167 
168  if ( !vfi.end() )
169  m_vflist.push_back( vfi );
170  }
171  }
172 
173  sort(m_vflist.begin(), m_vflist.end(), localityCompare);
174  return m_vflist;
175  }
176 
177  Source( AptDatabase &db ) : m_db( db ) {}
178 
180  return InternalList( *this );
181  }
182 
184  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  const pkgCache::VerFile* b)
190  {
191  if (a == 0 && b == 0)
192  return false;
193  if (a == 0)
194  return true;
195  if (b == 0)
196  return false;
197 
198  if (a->File == b->File)
199  return a->Offset < b->Offset;
200  return a->File < b->File;
201  }
202 
203  void invalidate() {
205  lastFile = pkgCache::PkgFileIterator();
206  }
207 
208  std::string getRecord( Internal vfi ) {
209  if ( vfi.Cache() == 0 || vfi.end() )
210  return "";
211 
212  if ((lastFile.Cache() == 0)
213  || vfi->File + m_db.cache().PkgFileP != lastFile)
214  {
215  lastFile = pkgCache::PkgFileIterator(
216  m_db.cache(), vfi->File + m_db.cache().PkgFileP);
217  if (!lastFile.IsOk())
218  throw wibble::exception::System(
219  std::string("Reading the"
220  " data record for a package from file ")
221  + lastFile.FileName() );
222  if (file.IsOpen())
223  file.Close();
224  if (!file.Open(lastFile.FileName(), FileFd::ReadOnly))
225  throw wibble::exception::System( std::string("Opening file ")
226  + lastFile.FileName() );
227  lastOffset = 0;
228  }
229 
230  // If we start near were we ended, avoid a seek
231  // and enlarge the read a bit
232  size_t slack = vfi->Offset - lastOffset;
233  if ( slack > 128 ) // mornfall: was 8, making it 128
234  {
235  slack = 0;
236  if ( !file.Seek( vfi->Offset ) )
237  throw wibble::exception::System(
238  std::string("Cannot seek to package record in file ")
239  + lastFile.FileName() );
240  }
241 
242  char buffer[vfi->Size + slack + 1];
243  if (!file.Read(buffer, vfi->Size + slack))
244  throw wibble::exception::System(
245  std::string("Cannot read package "
246  "record in file ") + lastFile.FileName() );
247 
248  buffer[vfi->Size + slack] = '\0';
249  //cerr << "Data read (slack: " << slack << ")" << endl;
250 
251  lastOffset = vfi->Offset + vfi->Size;
252 
253  return string(buffer+slack);
254  }
255 
257  Token t;
258  t._id = getInternal< Name >( i ) + "_" + getInternal< Version >( i );
259  return t;
260  }
261 
262  template< PropertyId p >
264  Parser rec( getRecord( i ) );
265  return rec.get< p >();
266  }
267 };
268 
269 template<> inline std::string Source::getInternal< Record >( Internal i ) {
270  assert( !i.end() );
271  return getRecord( i );
272 }
273 
274 inline const Internal InternalList::head() const {
275  return pkgCache::VerFileIterator( m_source->m_db.cache(),
276  m_source->vfList()[ m_idx ] );
277 }
278 
279 inline bool InternalList::empty() const {
280  return m_idx == m_source->vfList().size();
281 }
282 
283 
284 }
285 }
286 }
287 
288 #endif