1 /*
2 * Copyright (c) 2007, Novell Inc.
3 *
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
6 */
7
8 /*
9 * poolid.c
10 *
11 * Id management
12 */
13
14 #include <stdlib.h>
15 #include <string.h>
16 #include <stdio.h>
17
18 #include "pool.h"
19 #include "poolid.h"
20 #include "poolid_private.h"
21 #include "util.h"
22
23
24 /* intern string into pool, return id */
25
26 Id
pool_str2id(Pool * pool,const char * str,int create)27 pool_str2id(Pool *pool, const char *str, int create)
28 {
29 int oldnstrings = pool->ss.nstrings;
30 Id id = stringpool_str2id(&pool->ss, str, create);
31 if (create && pool->whatprovides && oldnstrings != pool->ss.nstrings && (id & WHATPROVIDES_BLOCK) == 0)
32 {
33 /* grow whatprovides array */
34 pool->whatprovides = solv_realloc(pool->whatprovides, (id + (WHATPROVIDES_BLOCK + 1)) * sizeof(Offset));
35 memset(pool->whatprovides + id, 0, (WHATPROVIDES_BLOCK + 1) * sizeof(Offset));
36 }
37 return id;
38 }
39
40 Id
pool_strn2id(Pool * pool,const char * str,unsigned int len,int create)41 pool_strn2id(Pool *pool, const char *str, unsigned int len, int create)
42 {
43 int oldnstrings = pool->ss.nstrings;
44 Id id = stringpool_strn2id(&pool->ss, str, len, create);
45 if (create && pool->whatprovides && oldnstrings != pool->ss.nstrings && (id & WHATPROVIDES_BLOCK) == 0)
46 {
47 /* grow whatprovides array */
48 pool->whatprovides = solv_realloc(pool->whatprovides, (id + (WHATPROVIDES_BLOCK + 1)) * sizeof(Offset));
49 memset(pool->whatprovides + id, 0, (WHATPROVIDES_BLOCK + 1) * sizeof(Offset));
50 }
51 return id;
52 }
53
54 void
pool_resize_rels_hash(Pool * pool,int numnew)55 pool_resize_rels_hash(Pool *pool, int numnew)
56 {
57 Hashval h, hh, hashmask;
58 Hashtable hashtbl;
59 int i;
60 Reldep *rd;
61
62 if (numnew <= 0)
63 return;
64 hashmask = mkmask(pool->nrels + numnew);
65 if (hashmask <= pool->relhashmask)
66 return; /* same as before */
67
68 /* realloc hash table */
69 pool->relhashmask = hashmask;
70 solv_free(pool->relhashtbl);
71 pool->relhashtbl = hashtbl = solv_calloc(hashmask + 1, sizeof(Id));
72
73 /* rehash all rels into new hashtable */
74 for (i = 1, rd = pool->rels + i; i < pool->nrels; i++, rd++)
75 {
76 h = relhash(rd->name, rd->evr, rd->flags) & hashmask;
77 hh = HASHCHAIN_START;
78 while (hashtbl[h])
79 h = HASHCHAIN_NEXT(h, hh, hashmask);
80 hashtbl[h] = i;
81 }
82 }
83
84 Id
pool_rel2id(Pool * pool,Id name,Id evr,int flags,int create)85 pool_rel2id(Pool *pool, Id name, Id evr, int flags, int create)
86 {
87 Hashval h, hh, hashmask;
88 Id id;
89 Hashtable hashtbl;
90 Reldep *ran;
91
92
93 /* extend hashtable if needed */
94 hashmask = pool->relhashmask;
95 if ((Hashval)pool->nrels * 2 > hashmask)
96 {
97 pool_resize_rels_hash(pool, REL_BLOCK);
98 hashmask = pool->relhashmask;
99 }
100 hashtbl = pool->relhashtbl;
101
102 /* compute hash and check for match */
103 h = relhash(name, evr, flags) & hashmask;
104 hh = HASHCHAIN_START;
105 ran = pool->rels;
106 while ((id = hashtbl[h]) != 0)
107 {
108 if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags)
109 break;
110 h = HASHCHAIN_NEXT(h, hh, hashmask);
111 }
112 if (id)
113 return MAKERELDEP(id);
114
115 if (!create)
116 return ID_NULL;
117
118 id = pool->nrels++;
119 /* extend rel space if needed */
120 pool->rels = solv_extend(pool->rels, id, 1, sizeof(Reldep), REL_BLOCK);
121 hashtbl[h] = id;
122 ran = pool->rels + id;
123 ran->name = name;
124 ran->evr = evr;
125 ran->flags = flags;
126
127 /* extend whatprovides_rel if needed */
128 if (pool->whatprovides_rel && (id & WHATPROVIDES_BLOCK) == 0)
129 {
130 pool->whatprovides_rel = solv_realloc2(pool->whatprovides_rel, id + (WHATPROVIDES_BLOCK + 1), sizeof(Offset));
131 memset(pool->whatprovides_rel + id, 0, (WHATPROVIDES_BLOCK + 1) * sizeof(Offset));
132 }
133 return MAKERELDEP(id);
134 }
135
136
137 /* Id -> String
138 * for rels (returns name only) and strings
139 */
140 const char *
pool_id2str(const Pool * pool,Id id)141 pool_id2str(const Pool *pool, Id id)
142 {
143 while (ISRELDEP(id))
144 {
145 Reldep *rd = GETRELDEP(pool, id);
146 id = rd->name;
147 }
148 return pool->ss.stringspace + pool->ss.strings[id];
149 }
150
151 static const char *rels[] = {
152 " ! ",
153 " > ",
154 " = ",
155 " >= ",
156 " < ",
157 " <> ",
158 " <= ",
159 " <=> "
160 };
161
162
163 /* get operator for RelId */
164 const char *
pool_id2rel(const Pool * pool,Id id)165 pool_id2rel(const Pool *pool, Id id)
166 {
167 Reldep *rd;
168 if (!ISRELDEP(id))
169 return "";
170 rd = GETRELDEP(pool, id);
171
172 switch (rd->flags)
173 {
174 /* debian special cases < and > */
175 /* haiku special cases <> (maybe we should use != for the others as well */
176 case 0: case REL_EQ: case REL_GT | REL_EQ:
177 case REL_LT | REL_EQ: case REL_LT | REL_EQ | REL_GT:
178 #if !defined(DEBIAN) && !defined(MULTI_SEMANTICS)
179 case REL_LT: case REL_GT:
180 #endif
181 #if !defined(HAIKU) && !defined(MULTI_SEMANTICS)
182 case REL_LT | REL_GT:
183 #endif
184 return rels[rd->flags];
185 #if defined(DEBIAN) || defined(MULTI_SEMANTICS)
186 case REL_GT:
187 return pool->disttype == DISTTYPE_DEB ? " >> " : rels[rd->flags];
188 case REL_LT:
189 return pool->disttype == DISTTYPE_DEB ? " << " : rels[rd->flags];
190 #endif
191 #if defined(HAIKU) || defined(MULTI_SEMANTICS)
192 case REL_LT | REL_GT:
193 return pool->disttype == DISTTYPE_HAIKU ? " != " : rels[rd->flags];
194 #endif
195 case REL_AND:
196 return pool->disttype == DISTTYPE_RPM ? " and " : " & ";
197 case REL_OR:
198 return pool->disttype == DISTTYPE_RPM ? " or " : " | ";
199 case REL_WITH:
200 return pool->disttype == DISTTYPE_RPM ? " with " : " + ";
201 case REL_WITHOUT:
202 return pool->disttype == DISTTYPE_RPM ? " without " : " - ";
203 case REL_NAMESPACE:
204 return " NAMESPACE "; /* actually not used in dep2str */
205 case REL_ARCH:
206 return ".";
207 case REL_MULTIARCH:
208 return ":";
209 case REL_FILECONFLICT:
210 return " FILECONFLICT ";
211 case REL_COND:
212 return pool->disttype == DISTTYPE_RPM ? " if " : " IF ";
213 case REL_UNLESS:
214 return pool->disttype == DISTTYPE_RPM ? " unless " : " UNLESS ";
215 case REL_COMPAT:
216 return " compat >= ";
217 case REL_KIND:
218 return " KIND ";
219 case REL_ELSE:
220 return pool->disttype == DISTTYPE_RPM ? " else " : " ELSE ";
221 case REL_CONDA:
222 return " ";
223 case REL_ERROR:
224 return " ERROR ";
225 default:
226 break;
227 }
228 return " ??? ";
229 }
230
231
232 /* get e:v.r for Id */
233 const char *
pool_id2evr(const Pool * pool,Id id)234 pool_id2evr(const Pool *pool, Id id)
235 {
236 Reldep *rd;
237 if (!ISRELDEP(id))
238 return "";
239 rd = GETRELDEP(pool, id);
240 if (ISRELDEP(rd->evr))
241 return "(REL)";
242 return pool->ss.stringspace + pool->ss.strings[rd->evr];
243 }
244
245 static int
dep2strlen(const Pool * pool,Id id)246 dep2strlen(const Pool *pool, Id id)
247 {
248 int l = 0;
249
250 while (ISRELDEP(id))
251 {
252 Reldep *rd = GETRELDEP(pool, id);
253 /* add 2 for parens */
254 l += 2 + dep2strlen(pool, rd->name) + strlen(pool_id2rel(pool, id));
255 id = rd->evr;
256 }
257 return l + strlen(pool->ss.stringspace + pool->ss.strings[id]);
258 }
259
260 static void
dep2strcpy(const Pool * pool,char * p,Id id,int oldrel)261 dep2strcpy(const Pool *pool, char *p, Id id, int oldrel)
262 {
263 while (ISRELDEP(id))
264 {
265 Reldep *rd = GETRELDEP(pool, id);
266 int rel = rd->flags;
267 if (oldrel == REL_AND || oldrel == REL_OR || oldrel == REL_WITH || oldrel == REL_WITHOUT || oldrel == REL_COND || oldrel == REL_UNLESS || oldrel == REL_ELSE || oldrel == -1)
268 if (rel == REL_AND || rel == REL_OR || rel == REL_WITH || rel == REL_WITHOUT || rel == REL_COND || rel == REL_UNLESS || rel == REL_ELSE)
269 if ((oldrel != rel || rel == REL_COND || rel == REL_UNLESS || rel == REL_ELSE) && !((oldrel == REL_COND || oldrel == REL_UNLESS) && rel == REL_ELSE))
270 {
271 *p++ = '(';
272 dep2strcpy(pool, p, rd->name, rd->flags);
273 p += strlen(p);
274 strcpy(p, pool_id2rel(pool, id));
275 p += strlen(p);
276 dep2strcpy(pool, p, rd->evr, rd->flags);
277 strcat(p, ")");
278 return;
279 }
280 if (rd->flags == REL_KIND)
281 {
282 dep2strcpy(pool, p, rd->evr, rd->flags);
283 p += strlen(p);
284 *p++ = ':';
285 id = rd->name;
286 oldrel = rd->flags;
287 continue;
288 }
289 dep2strcpy(pool, p, rd->name, rd->flags);
290 p += strlen(p);
291 if (rd->flags == REL_NAMESPACE)
292 {
293 *p++ = '(';
294 dep2strcpy(pool, p, rd->evr, rd->flags);
295 strcat(p, ")");
296 return;
297 }
298 if (rd->flags == REL_FILECONFLICT)
299 {
300 *p = 0;
301 return;
302 }
303 strcpy(p, pool_id2rel(pool, id));
304 p += strlen(p);
305 id = rd->evr;
306 oldrel = rd->flags;
307 }
308 strcpy(p, pool->ss.stringspace + pool->ss.strings[id]);
309 }
310
311 const char *
pool_dep2str(Pool * pool,Id id)312 pool_dep2str(Pool *pool, Id id)
313 {
314 char *p;
315 if (!ISRELDEP(id))
316 return pool->ss.stringspace + pool->ss.strings[id];
317 p = pool_alloctmpspace(pool, dep2strlen(pool, id) + 1);
318 dep2strcpy(pool, p, id, pool->disttype == DISTTYPE_RPM ? -1 : 0);
319 return p;
320 }
321
322 static void
pool_free_rels_hash(Pool * pool)323 pool_free_rels_hash(Pool *pool)
324 {
325 pool->relhashtbl = solv_free(pool->relhashtbl);
326 pool->relhashmask = 0;
327 }
328
329 void
pool_shrink_strings(Pool * pool)330 pool_shrink_strings(Pool *pool)
331 {
332 /* free excessive big hashes */
333 if (pool->ss.stringhashmask && pool->ss.stringhashmask > mkmask(pool->ss.nstrings + 8192))
334 stringpool_freehash(&pool->ss);
335 stringpool_shrink(&pool->ss);
336 }
337
338 void
pool_shrink_rels(Pool * pool)339 pool_shrink_rels(Pool *pool)
340 {
341 /* free excessive big hashes */
342 if (pool->relhashmask && pool->relhashmask > mkmask(pool->nrels + 4096))
343 pool_free_rels_hash(pool);
344 pool->rels = solv_extend_resize(pool->rels, pool->nrels, sizeof(Reldep), REL_BLOCK);
345 }
346
347 /* free all hash tables */
348 void
pool_freeidhashes(Pool * pool)349 pool_freeidhashes(Pool *pool)
350 {
351 stringpool_freehash(&pool->ss);
352 pool_free_rels_hash(pool);
353 }
354
355 /* EOF */
356