Imported Upstream version 0.6.35
[platform/upstream/libsolv.git] / src / poolid.c
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
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
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
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
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 *
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 *
165 pool_id2rel(const Pool *pool, Id id)
166 {
167   Reldep *rd;
168   if (!ISRELDEP(id))
169     return "";
170   rd = GETRELDEP(pool, id);
171   switch (rd->flags)
172     {
173     /* debian special cases < and > */
174     /* haiku special cases <> (maybe we should use != for the others as well */
175     case 0: case REL_EQ: case REL_GT | REL_EQ:
176     case REL_LT | REL_EQ: case REL_LT | REL_EQ | REL_GT:
177 #if !defined(DEBIAN) && !defined(MULTI_SEMANTICS)
178     case REL_LT: case REL_GT:
179 #endif
180 #if !defined(HAIKU) && !defined(MULTI_SEMANTICS)
181     case REL_LT | REL_GT:
182 #endif
183       return rels[rd->flags];
184 #if defined(DEBIAN) || defined(MULTI_SEMANTICS)
185     case REL_GT:
186       return pool->disttype == DISTTYPE_DEB ? " >> " : rels[rd->flags];
187     case REL_LT:
188       return pool->disttype == DISTTYPE_DEB ? " << " : rels[rd->flags];
189 #endif
190 #if defined(HAIKU) || defined(MULTI_SEMANTICS)
191     case REL_LT | REL_GT:
192       return pool->disttype == DISTTYPE_HAIKU ? " != " : rels[rd->flags];
193 #endif
194     case REL_AND:
195       return pool->disttype == DISTTYPE_RPM ? " and " : " & ";
196     case REL_OR:
197       return pool->disttype == DISTTYPE_RPM ? " or " : " | ";
198     case REL_WITH:
199       return pool->disttype == DISTTYPE_RPM ? " with " : " + ";
200     case REL_WITHOUT:
201       return pool->disttype == DISTTYPE_RPM ? " without " : " - ";
202     case REL_NAMESPACE:
203       return " NAMESPACE ";     /* actually not used in dep2str */
204     case REL_ARCH:
205       return ".";
206     case REL_MULTIARCH:
207       return ":";
208     case REL_FILECONFLICT:
209       return " FILECONFLICT ";
210     case REL_COND:
211       return pool->disttype == DISTTYPE_RPM ? " if " : " IF ";
212     case REL_UNLESS:
213       return pool->disttype == DISTTYPE_RPM ? " unless " : " UNLESS ";
214     case REL_COMPAT:
215       return " compat >= ";
216     case REL_KIND:
217       return " KIND ";
218     case REL_ELSE:
219       return pool->disttype == DISTTYPE_RPM ? " else " : " ELSE ";
220     case REL_ERROR:
221       return " ERROR ";
222     default:
223       break;
224     }
225   return " ??? ";
226 }
227
228
229 /* get e:v.r for Id */
230 const char *
231 pool_id2evr(const Pool *pool, Id id)
232 {
233   Reldep *rd;
234   if (!ISRELDEP(id))
235     return "";
236   rd = GETRELDEP(pool, id);
237   if (ISRELDEP(rd->evr))
238     return "(REL)";
239   return pool->ss.stringspace + pool->ss.strings[rd->evr];
240 }
241
242 static int
243 dep2strlen(const Pool *pool, Id id)
244 {
245   int l = 0;
246
247   while (ISRELDEP(id))
248     {
249       Reldep *rd = GETRELDEP(pool, id);
250       /* add 2 for parens */
251       l += 2 + dep2strlen(pool, rd->name) + strlen(pool_id2rel(pool, id));
252       id = rd->evr;
253     }
254   return l + strlen(pool->ss.stringspace + pool->ss.strings[id]);
255 }
256
257 static void
258 dep2strcpy(const Pool *pool, char *p, Id id, int oldrel)
259 {
260   while (ISRELDEP(id))
261     {
262       Reldep *rd = GETRELDEP(pool, id);
263       int rel = rd->flags;
264       if (oldrel == REL_AND || oldrel == REL_OR || oldrel == REL_WITH || oldrel == REL_WITHOUT || oldrel == REL_COND || oldrel == REL_UNLESS || oldrel == REL_ELSE || oldrel == -1)
265         if (rel == REL_AND || rel == REL_OR || rel == REL_WITH || rel == REL_WITHOUT || rel == REL_COND || rel == REL_UNLESS || rel == REL_ELSE)
266           if ((oldrel != rel || rel == REL_COND || rel == REL_UNLESS || rel == REL_ELSE) && !((oldrel == REL_COND || oldrel == REL_UNLESS) && rel == REL_ELSE))
267             {
268               *p++ = '(';
269               dep2strcpy(pool, p, rd->name, rd->flags);
270               p += strlen(p);
271               strcpy(p, pool_id2rel(pool, id));
272               p += strlen(p);
273               dep2strcpy(pool, p, rd->evr, rd->flags);
274               strcat(p, ")");
275               return;
276             }
277       if (rd->flags == REL_KIND)
278         {
279           dep2strcpy(pool, p, rd->evr, rd->flags);
280           p += strlen(p);
281           *p++ = ':';
282           id = rd->name;
283           oldrel = rd->flags;
284           continue;
285         }
286       dep2strcpy(pool, p, rd->name, rd->flags);
287       p += strlen(p);
288       if (rd->flags == REL_NAMESPACE)
289         {
290           *p++ = '(';
291           dep2strcpy(pool, p, rd->evr, rd->flags);
292           strcat(p, ")");
293           return;
294         }
295       if (rd->flags == REL_FILECONFLICT)
296         {
297           *p = 0;
298           return;
299         }
300       strcpy(p, pool_id2rel(pool, id));
301       p += strlen(p);
302       id = rd->evr;
303       oldrel = rd->flags;
304     }
305   strcpy(p, pool->ss.stringspace + pool->ss.strings[id]);
306 }
307
308 const char *
309 pool_dep2str(Pool *pool, Id id)
310 {
311   char *p;
312   if (!ISRELDEP(id))
313     return pool->ss.stringspace + pool->ss.strings[id];
314   p = pool_alloctmpspace(pool, dep2strlen(pool, id) + 1);
315   dep2strcpy(pool, p, id, pool->disttype == DISTTYPE_RPM ? -1 : 0);
316   return p;
317 }
318
319 static void
320 pool_free_rels_hash(Pool *pool)
321 {
322   pool->relhashtbl = solv_free(pool->relhashtbl);
323   pool->relhashmask = 0;
324 }
325
326 void
327 pool_shrink_strings(Pool *pool)
328 {
329   /* free excessive big hashes */
330   if (pool->ss.stringhashmask && pool->ss.stringhashmask > mkmask(pool->ss.nstrings + 8192))
331     stringpool_freehash(&pool->ss);
332   stringpool_shrink(&pool->ss);
333 }
334
335 void
336 pool_shrink_rels(Pool *pool)
337 {
338   /* free excessive big hashes */
339   if (pool->relhashmask && pool->relhashmask > mkmask(pool->nrels + 4096))
340     pool_free_rels_hash(pool);
341   pool->rels = solv_extend_resize(pool->rels, pool->nrels, sizeof(Reldep), REL_BLOCK);
342 }
343
344 /* free all hash tables */
345 void
346 pool_freeidhashes(Pool *pool)
347 {
348   stringpool_freehash(&pool->ss);
349   pool_free_rels_hash(pool);
350 }
351
352 /* EOF */