1 ////////////////////////////////////////////////////////////////////////
2 // FILE: pkgdb.cpp
3 // AUTHOR: Johannes Winkelmann, jw@tks6.net
4 // COPYRIGHT: (c) 2002 by Johannes Winkelmann
5 // ---------------------------------------------------------------------
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 ////////////////////////////////////////////////////////////////////////
11
12 #include <algorithm>
13 #include <fstream>
14 #include <map>
15 #include <iostream>
16 using namespace std;
17
18 #include <cstring>
19 #include <cstdio>
20
21 #include <fnmatch.h>
22
23 #include "pkgdb.h"
24 #include "datafileparser.h"
25 #include "stringhelper.h"
26 #include "pg_regex.h"
27
28
29 const string PkgDB::PKGDB = "/var/lib/pkg/db";
30 const string PkgDB::ALIAS_STORE = SYSCONFDIR"/prt-get.aliases";
31
32 /*!
33 Create a PkgDB object
34 */
35 PkgDB::PkgDB( const string& installRoot )
36 : m_isLoaded( false ),
37 m_installRoot( installRoot )
38 {
39 }
40
41 /*!
42 Check whether a package is installed
43
44 \param name the name of the package to check
45 \param isAlias whether a package is installed as alias
46 \param aliasOriginalName the original name of an aliased package
47
48 \return whether package \a name is installed
49 */
50 bool PkgDB::isInstalled( const string& name,
51 bool useAlias,
52 bool* isAlias,
53 string* aliasOrignalName ) const
54 {
55 if ( !load() ) {
56 return false;
57 }
58
59 bool installed = m_packages.find( name ) != m_packages.end();
60 if (!installed && useAlias) {
61 string provider;
62 installed = aliasExistsFor(name, provider);
63
64 if (isAlias) {
65 *isAlias = installed;
66
67 if (installed && aliasOrignalName) {
68 *aliasOrignalName = provider;
69 }
70 }
71 } else {
72 if (isAlias) {
73 *isAlias = false;
74 }
75 }
76
77 return installed;
78 }
79
80
81 bool PkgDB::aliasExistsFor(const string& name, string& providerName) const
82 {
83 // when used the first time, split alias names
84 if (m_splitAliases.size() < m_aliases.size()) {
85 map<string, string>::iterator it = m_aliases.begin();
86 for (; it != m_aliases.end(); ++it) {
87 StringHelper::split(it->second, ',',
88 m_splitAliases[it->first]);
89 }
90 }
91
92 map<string, vector<string> >::iterator it = m_splitAliases.begin();
93 for (; it != m_splitAliases.end(); ++it) {
94 if (find(it->second.begin(), it->second.end(), name) !=
95 it->second.end()) {
96 providerName = it->first;
97 return true;
98 }
99 }
100
101 return false;
102 }
103
104 /*!
105 load the package db
106 */
107 bool PkgDB::load() const
108 {
109 if ( m_isLoaded ) {
110 return true;
111 }
112
113 #if 0
114 // check this one out to see a really slow IO library :-(
115
116
117 ifstream db( PKGDB );
118 string line;
119 bool emptyLine = true;
120 while ( db.good() ) {
121 getline( db, line );
122 if ( emptyLine ) {
123 if ( !line.empty() ) {
124 m_packages.push_back( line );
125 }
126 emptyLine = false;
127 }
128 if ( line == "" ) {
129 emptyLine = true;
130 }
131 }
132 db.close();
133 #endif
134
135 std::map<std::string, std::string> aliases;
136 DataFileParser::parse(ALIAS_STORE, aliases);
137
138 const int length = 256;
139 char line[length];
140 bool emptyLine = true;
141 bool nameRead = false;
142 string name;
143
144 string pkgdb = "";
145 if (m_installRoot != "") {
146 pkgdb = m_installRoot;
147 }
148 pkgdb += PKGDB;
149
150 FILE* fp = fopen( pkgdb.c_str(), "r" );
151 if ( fp ) {
152 while ( fgets( line, length, fp ) ) {
153 if ( emptyLine ) {
154 line[strlen(line)-1] = '\0';
155 name = line;
156 emptyLine = false;
157 nameRead = true;
158 } else if ( nameRead ) {
159 line[strlen(line)-1] = '\0';
160 m_packages[ name ] = line;
161 nameRead = false;
162 if (aliases.find(name) != aliases.end()) {
163 m_aliases[name] = aliases[name];
164 }
165 }
166 if ( line[0] == '\n' ) {
167 emptyLine = true;
168 }
169
170 }
171 } else {
172 return false;
173 }
174
175 m_isLoaded = true;
176
177 fclose( fp );
178
179 return true;
180 }
181
182 /*!
183 return a map of installed packages, where the key is the package name and
184 the value is the version/release string
185 \return a map of installed packages (key=name, value=version/release)
186 */
187 const map<string, string>& PkgDB::installedPackages()
188 {
189 load();
190 return m_packages;
191 }
192
193 /*!
194 \return a package's version and release or an empty string if not found
195 */
196 string PkgDB::getPackageVersion( const string& name ) const
197 {
198 if ( !load() ) {
199 return "";
200 }
201
202 map<string, string>::const_iterator it = m_packages.find( name );
203 if ( it == m_packages.end() ) {
204 return "";
205 }
206
207 return it->second;
208 }
209
210 /*!
211 Search packages for a match of \a pattern in name. The name can
212 contain shell wildcards.
213
214 \param pattern the pattern to be found
215 \return a list of matching packages
216 */
217 void PkgDB::getMatchingPackages( const string& pattern,
218 map<string,string>& target,
219 bool useRegex ) const
220 {
221 if ( !load() ) {
222 return;
223 }
224
225 RegEx re(pattern);
226 map<string, string>::const_iterator it = m_packages.begin();
227 if (useRegex) {
228 for ( ; it != m_packages.end(); ++it ) {
229 if (re.match(it->first)) {
230 target[it->first] = it->second;
231 }
232 }
233 } else {
234 for ( ; it != m_packages.end(); ++it ) {
235 // I assume fnmatch will be quite fast for "match all" (*), so
236 // I didn't add a boolean to check for this explicitely
237 if ( fnmatch( pattern.c_str(), it->first.c_str(), 0 ) == 0 ) {
238 target[it->first] = it->second;
239 }
240 }
241 }
242 }
|