- start support for Fedora comps format
[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;
58   unsigned int hh;
59   Hashmask hashmask;
60   int i;
61   Id id;
62   Hashtable hashtbl;
63   Reldep *ran;
64
65   hashmask = pool->relhashmask;
66   hashtbl = pool->relhashtbl;
67   ran = pool->rels;
68   
69   /* extend hashtable if needed */
70   if (pool->nrels * 2 > hashmask)
71     {
72       solv_free(pool->relhashtbl);
73       pool->relhashmask = hashmask = mkmask(pool->nrels + REL_BLOCK);
74       pool->relhashtbl = hashtbl = solv_calloc(hashmask + 1, sizeof(Id));
75       /* rehash all rels into new hashtable */
76       for (i = 1; i < pool->nrels; i++)
77         {
78           h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask;
79           hh = HASHCHAIN_START;
80           while (hashtbl[h])
81             h = HASHCHAIN_NEXT(h, hh, hashmask);
82           hashtbl[h] = i;
83         }
84     }
85   
86   /* compute hash and check for match */
87   h = relhash(name, evr, flags) & hashmask;
88   hh = HASHCHAIN_START;
89   while ((id = hashtbl[h]) != 0)
90     {
91       if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags)
92         break;
93       h = HASHCHAIN_NEXT(h, hh, hashmask);
94     }
95   if (id)
96     return MAKERELDEP(id);
97
98   if (!create)
99     return ID_NULL;
100
101   id = pool->nrels++;
102   /* extend rel space if needed */
103   pool->rels = solv_extend(pool->rels, id, 1, sizeof(Reldep), REL_BLOCK);
104   hashtbl[h] = id;
105   ran = pool->rels + id;
106   ran->name = name;
107   ran->evr = evr;
108   ran->flags = flags;
109
110   /* extend whatprovides_rel if needed */
111   if (pool->whatprovides_rel && (id & WHATPROVIDES_BLOCK) == 0)
112     {
113       pool->whatprovides_rel = solv_realloc2(pool->whatprovides_rel, id + (WHATPROVIDES_BLOCK + 1), sizeof(Offset));
114       memset(pool->whatprovides_rel + id, 0, (WHATPROVIDES_BLOCK + 1) * sizeof(Offset));
115     }
116   return MAKERELDEP(id);
117 }
118
119
120 /* Id -> String
121  * for rels (returns name only) and strings
122  */ 
123 const char *
124 pool_id2str(const Pool *pool, Id id)
125 {
126   if (ISRELDEP(id))
127     {
128       Reldep *rd = GETRELDEP(pool, id);
129       if (ISRELDEP(rd->name))
130         return "REL";
131       return pool->ss.stringspace + pool->ss.strings[rd->name];
132     }
133   return pool->ss.stringspace + pool->ss.strings[id];
134 }
135
136 static const char *rels[] = {
137   " ! ",
138 #ifndef DEBIAN_SEMANTICS
139   " > ",
140 #else
141   " >> ",
142 #endif
143   " = ",
144   " >= ",
145 #ifndef DEBIAN_SEMANTICS
146   " < ",
147 #else
148   " << ",
149 #endif
150   " <> ",
151   " <= ",
152   " <=> "
153 };
154
155
156 /* get operator for RelId */
157 const char *
158 pool_id2rel(const Pool *pool, Id id)
159 {
160   Reldep *rd;
161   if (!ISRELDEP(id))
162     return "";
163   rd = GETRELDEP(pool, id);
164   switch (rd->flags)
165     {
166     case 0: case 1: case 2: case 3:
167     case 4: case 5: case 6: case 7:
168       return rels[rd->flags & 7];
169     case REL_AND:
170       return " & ";
171     case REL_OR:
172       return " | ";
173     case REL_WITH:
174       return " + ";
175     case REL_NAMESPACE:
176       return " NAMESPACE ";     /* actually not used in dep2str */
177     case REL_ARCH:
178       return ".";
179     case REL_FILECONFLICT:
180       return " FILECONFLICT ";
181     case REL_COND:
182       return " IF ";
183     default:
184       break;
185     }
186   return " ??? ";
187 }
188
189
190 /* get e:v.r for Id */
191 const char *
192 pool_id2evr(const Pool *pool, Id id)
193 {
194   Reldep *rd;
195   if (!ISRELDEP(id))
196     return "";
197   rd = GETRELDEP(pool, id);
198   if (ISRELDEP(rd->evr))
199     return "(REL)";
200   return pool->ss.stringspace + pool->ss.strings[rd->evr];
201 }
202
203 static int
204 dep2strlen(const Pool *pool, Id id)
205 {
206   int l = 0;
207
208   while (ISRELDEP(id))
209     {
210       Reldep *rd = GETRELDEP(pool, id);
211       /* add 2 for parens */
212       l += 2 + dep2strlen(pool, rd->name) + strlen(pool_id2rel(pool, id));
213       id = rd->evr;
214     }
215   return l + strlen(pool->ss.stringspace + pool->ss.strings[id]);
216 }
217
218 static void
219 dep2strcpy(const Pool *pool, char *p, Id id, int oldrel)
220 {
221   while (ISRELDEP(id))
222     {
223       Reldep *rd = GETRELDEP(pool, id);
224       if (oldrel == REL_AND || oldrel == REL_OR || oldrel == REL_WITH)
225         if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_WITH)
226           if (oldrel != rd->flags)
227             {
228               *p++ = '(';
229               dep2strcpy(pool, p, rd->name, rd->flags);
230               p += strlen(p);
231               strcpy(p, pool_id2rel(pool, id));
232               p += strlen(p);
233               dep2strcpy(pool, p, rd->evr, rd->flags);
234               strcat(p, ")");
235               return;
236             }
237       dep2strcpy(pool, p, rd->name, rd->flags);
238       p += strlen(p);
239       if (rd->flags == REL_NAMESPACE)
240         {
241           *p++ = '(';
242           dep2strcpy(pool, p, rd->evr, rd->flags);
243           strcat(p, ")");
244           return;
245         }
246       if (rd->flags == REL_FILECONFLICT)
247         {
248           *p = 0;
249           return;
250         }
251       strcpy(p, pool_id2rel(pool, id));
252       p += strlen(p);
253       id = rd->evr;
254       oldrel = rd->flags;
255     }
256   strcpy(p, pool->ss.stringspace + pool->ss.strings[id]);
257 }
258
259 const char *
260 pool_dep2str(Pool *pool, Id id)
261 {
262   char *p;
263   if (!ISRELDEP(id))
264     return pool->ss.stringspace + pool->ss.strings[id];
265   p = pool_alloctmpspace(pool, dep2strlen(pool, id) + 1);
266   dep2strcpy(pool, p, id, 0);
267   return p;
268 }
269
270 void
271 pool_shrink_strings(Pool *pool)
272 {
273   stringpool_shrink(&pool->ss);
274 }
275
276 void
277 pool_shrink_rels(Pool *pool)
278 {
279   pool->rels = solv_extend_resize(pool->rels, pool->nrels, sizeof(Reldep), REL_BLOCK);
280 }
281
282 /* free all hash tables */
283 void
284 pool_freeidhashes(Pool *pool)
285 {
286   stringpool_freehash(&pool->ss);
287   pool->relhashtbl = solv_free(pool->relhashtbl);
288   pool->relhashmask = 0;
289 }
290
291 /* EOF */