bb8d4f6de26c0aff443b25cfb364638da62dbdd5
[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 Id
55 pool_rel2id(Pool *pool, Id name, Id evr, int flags, int create)
56 {
57   Hashval h, hh, hashmask;
58   int i;
59   Id id;
60   Hashtable hashtbl;
61   Reldep *ran;
62
63   hashmask = pool->relhashmask;
64   hashtbl = pool->relhashtbl;
65   ran = pool->rels;
66
67   /* extend hashtable if needed */
68   if ((Hashval)pool->nrels * 2 > hashmask)
69     {
70       solv_free(pool->relhashtbl);
71       pool->relhashmask = hashmask = mkmask(pool->nrels + REL_BLOCK);
72       pool->relhashtbl = hashtbl = solv_calloc(hashmask + 1, sizeof(Id));
73       /* rehash all rels into new hashtable */
74       for (i = 1; i < pool->nrels; i++)
75         {
76           h = relhash(ran[i].name, ran[i].evr, ran[i].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   /* compute hash and check for match */
85   h = relhash(name, evr, flags) & hashmask;
86   hh = HASHCHAIN_START;
87   while ((id = hashtbl[h]) != 0)
88     {
89       if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags)
90         break;
91       h = HASHCHAIN_NEXT(h, hh, hashmask);
92     }
93   if (id)
94     return MAKERELDEP(id);
95
96   if (!create)
97     return ID_NULL;
98
99   id = pool->nrels++;
100   /* extend rel space if needed */
101   pool->rels = solv_extend(pool->rels, id, 1, sizeof(Reldep), REL_BLOCK);
102   hashtbl[h] = id;
103   ran = pool->rels + id;
104   ran->name = name;
105   ran->evr = evr;
106   ran->flags = flags;
107
108   /* extend whatprovides_rel if needed */
109   if (pool->whatprovides_rel && (id & WHATPROVIDES_BLOCK) == 0)
110     {
111       pool->whatprovides_rel = solv_realloc2(pool->whatprovides_rel, id + (WHATPROVIDES_BLOCK + 1), sizeof(Offset));
112       memset(pool->whatprovides_rel + id, 0, (WHATPROVIDES_BLOCK + 1) * sizeof(Offset));
113     }
114   return MAKERELDEP(id);
115 }
116
117
118 /* Id -> String
119  * for rels (returns name only) and strings
120  */
121 const char *
122 pool_id2str(const Pool *pool, Id id)
123 {
124   while (ISRELDEP(id))
125     {
126       Reldep *rd = GETRELDEP(pool, id);
127       id = rd->name;
128     }
129   return pool->ss.stringspace + pool->ss.strings[id];
130 }
131
132 static const char *rels[] = {
133   " ! ",
134   " > ",
135   " = ",
136   " >= ",
137   " < ",
138   " <> ",
139   " <= ",
140   " <=> "
141 };
142
143
144 /* get operator for RelId */
145 const char *
146 pool_id2rel(const Pool *pool, Id id)
147 {
148   Reldep *rd;
149   if (!ISRELDEP(id))
150     return "";
151   rd = GETRELDEP(pool, id);
152   switch (rd->flags)
153     {
154     /* debian special cases < and > */
155     /* haiku special cases <> (maybe we should use != for the others as well */
156     case 0: case REL_EQ: case REL_GT | REL_EQ:
157     case REL_LT | REL_EQ: case REL_LT | REL_EQ | REL_GT:
158 #if !defined(DEBIAN) && !defined(MULTI_SEMANTICS)
159     case REL_LT: case REL_GT:
160 #endif
161 #if !defined(HAIKU) && !defined(MULTI_SEMANTICS)
162     case REL_LT | REL_GT:
163 #endif
164       return rels[rd->flags];
165 #if defined(DEBIAN) || defined(MULTI_SEMANTICS)
166     case REL_GT:
167       return pool->disttype == DISTTYPE_DEB ? " >> " : rels[rd->flags];
168     case REL_LT:
169       return pool->disttype == DISTTYPE_DEB ? " << " : rels[rd->flags];
170 #endif
171 #if defined(HAIKU) || defined(MULTI_SEMANTICS)
172     case REL_LT | REL_GT:
173       return pool->disttype == DISTTYPE_HAIKU ? " != " : rels[rd->flags];
174 #endif
175     case REL_AND:
176       return pool->disttype == DISTTYPE_RPM ? " and " : " & ";
177     case REL_OR:
178       return pool->disttype == DISTTYPE_RPM ? " or " : " | ";
179     case REL_WITH:
180       return pool->disttype == DISTTYPE_RPM ? " with " : " + ";
181     case REL_WITHOUT:
182       return pool->disttype == DISTTYPE_RPM ? " without " : " - ";
183     case REL_NAMESPACE:
184       return " NAMESPACE ";     /* actually not used in dep2str */
185     case REL_ARCH:
186       return ".";
187     case REL_MULTIARCH:
188       return ":";
189     case REL_FILECONFLICT:
190       return " FILECONFLICT ";
191     case REL_COND:
192       return pool->disttype == DISTTYPE_RPM ? " if " : " IF ";
193     case REL_UNLESS:
194       return pool->disttype == DISTTYPE_RPM ? " unless " : " UNLESS ";
195     case REL_COMPAT:
196       return " compat >= ";
197     case REL_KIND:
198       return " KIND ";
199     case REL_ELSE:
200       return pool->disttype == DISTTYPE_RPM ? " else " : " ELSE ";
201     case REL_ERROR:
202       return " ERROR ";
203     default:
204       break;
205     }
206   return " ??? ";
207 }
208
209
210 /* get e:v.r for Id */
211 const char *
212 pool_id2evr(const Pool *pool, Id id)
213 {
214   Reldep *rd;
215   if (!ISRELDEP(id))
216     return "";
217   rd = GETRELDEP(pool, id);
218   if (ISRELDEP(rd->evr))
219     return "(REL)";
220   return pool->ss.stringspace + pool->ss.strings[rd->evr];
221 }
222
223 static int
224 dep2strlen(const Pool *pool, Id id)
225 {
226   int l = 0;
227
228   while (ISRELDEP(id))
229     {
230       Reldep *rd = GETRELDEP(pool, id);
231       /* add 2 for parens */
232       l += 2 + dep2strlen(pool, rd->name) + strlen(pool_id2rel(pool, id));
233       id = rd->evr;
234     }
235   return l + strlen(pool->ss.stringspace + pool->ss.strings[id]);
236 }
237
238 static void
239 dep2strcpy(const Pool *pool, char *p, Id id, int oldrel)
240 {
241   while (ISRELDEP(id))
242     {
243       Reldep *rd = GETRELDEP(pool, id);
244       int rel = rd->flags;
245       if (oldrel == REL_AND || oldrel == REL_OR || oldrel == REL_WITH || oldrel == REL_WITHOUT || oldrel == REL_COND || oldrel == REL_UNLESS || oldrel == REL_ELSE || oldrel == -1)
246         if (rel == REL_AND || rel == REL_OR || rel == REL_WITH || rel == REL_WITHOUT || rel == REL_COND || rel == REL_UNLESS || rel == REL_ELSE)
247           if ((oldrel != rel || rel == REL_COND || rel == REL_UNLESS || rel == REL_ELSE) && !((oldrel == REL_COND || oldrel == REL_UNLESS) && rel == REL_ELSE))
248             {
249               *p++ = '(';
250               dep2strcpy(pool, p, rd->name, rd->flags);
251               p += strlen(p);
252               strcpy(p, pool_id2rel(pool, id));
253               p += strlen(p);
254               dep2strcpy(pool, p, rd->evr, rd->flags);
255               strcat(p, ")");
256               return;
257             }
258       if (rd->flags == REL_KIND)
259         {
260           dep2strcpy(pool, p, rd->evr, rd->flags);
261           p += strlen(p);
262           *p++ = ':';
263           id = rd->name;
264           oldrel = rd->flags;
265           continue;
266         }
267       dep2strcpy(pool, p, rd->name, rd->flags);
268       p += strlen(p);
269       if (rd->flags == REL_NAMESPACE)
270         {
271           *p++ = '(';
272           dep2strcpy(pool, p, rd->evr, rd->flags);
273           strcat(p, ")");
274           return;
275         }
276       if (rd->flags == REL_FILECONFLICT)
277         {
278           *p = 0;
279           return;
280         }
281       strcpy(p, pool_id2rel(pool, id));
282       p += strlen(p);
283       id = rd->evr;
284       oldrel = rd->flags;
285     }
286   strcpy(p, pool->ss.stringspace + pool->ss.strings[id]);
287 }
288
289 const char *
290 pool_dep2str(Pool *pool, Id id)
291 {
292   char *p;
293   if (!ISRELDEP(id))
294     return pool->ss.stringspace + pool->ss.strings[id];
295   p = pool_alloctmpspace(pool, dep2strlen(pool, id) + 1);
296   dep2strcpy(pool, p, id, pool->disttype == DISTTYPE_RPM ? -1 : 0);
297   return p;
298 }
299
300 void
301 pool_shrink_strings(Pool *pool)
302 {
303   stringpool_shrink(&pool->ss);
304 }
305
306 void
307 pool_shrink_rels(Pool *pool)
308 {
309   pool->rels = solv_extend_resize(pool->rels, pool->nrels, sizeof(Reldep), REL_BLOCK);
310 }
311
312 /* free all hash tables */
313 void
314 pool_freeidhashes(Pool *pool)
315 {
316   stringpool_freehash(&pool->ss);
317   pool->relhashtbl = solv_free(pool->relhashtbl);
318   pool->relhashmask = 0;
319 }
320
321 /* EOF */