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 (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 if (ISRELDEP(id)) 125 { 126 Reldep *rd = GETRELDEP(pool, id); 127 if (ISRELDEP(rd->name)) 128 return "REL"; 129 return pool->ss.stringspace + pool->ss.strings[rd->name]; 130 } 131 return pool->ss.stringspace + pool->ss.strings[id]; 132 } 133 134 static const char *rels[] = { 135 " ! ", 136 " > ", 137 " = ", 138 " >= ", 139 " < ", 140 " <> ", 141 " <= ", 142 " <=> " 143 }; 144 145 146 /* get operator for RelId */ 147 const char * 148 pool_id2rel(const Pool *pool, Id id) 149 { 150 Reldep *rd; 151 if (!ISRELDEP(id)) 152 return ""; 153 rd = GETRELDEP(pool, id); 154 switch (rd->flags) 155 { 156 case 0: case 2: case 3: 157 case 6: case 7: 158 #if !defined(DEBIAN) && !defined(MULTI_SEMANTICS) 159 case 1: case 4: 160 #endif 161 #if !defined(HAIKU) && !defined(MULTI_SEMANTICS) 162 case 5: 163 #endif 164 return rels[rd->flags]; 165 #if defined(DEBIAN) || defined(MULTI_SEMANTICS) 166 case 1: 167 return pool->disttype == DISTTYPE_DEB ? " >> " : rels[rd->flags]; 168 case 4: 169 return pool->disttype == DISTTYPE_DEB ? " << " : rels[rd->flags]; 170 #endif 171 #if defined(HAIKU) || defined(MULTI_SEMANTICS) 172 case 5: 173 return pool->disttype == DISTTYPE_HAIKU ? " != " : rels[rd->flags]; 174 #endif 175 case REL_AND: 176 return " & "; 177 case REL_OR: 178 return " | "; 179 case REL_WITH: 180 return " + "; 181 case REL_NAMESPACE: 182 return " NAMESPACE "; /* actually not used in dep2str */ 183 case REL_ARCH: 184 return "."; 185 case REL_FILECONFLICT: 186 return " FILECONFLICT "; 187 case REL_COND: 188 return " IF "; 189 case REL_COMPAT: 190 return " compat >= "; 191 default: 192 break; 193 } 194 return " ??? "; 195 } 196 197 198 /* get e:v.r for Id */ 199 const char * 200 pool_id2evr(const Pool *pool, Id id) 201 { 202 Reldep *rd; 203 if (!ISRELDEP(id)) 204 return ""; 205 rd = GETRELDEP(pool, id); 206 if (ISRELDEP(rd->evr)) 207 return "(REL)"; 208 return pool->ss.stringspace + pool->ss.strings[rd->evr]; 209 } 210 211 static int 212 dep2strlen(const Pool *pool, Id id) 213 { 214 int l = 0; 215 216 while (ISRELDEP(id)) 217 { 218 Reldep *rd = GETRELDEP(pool, id); 219 /* add 2 for parens */ 220 l += 2 + dep2strlen(pool, rd->name) + strlen(pool_id2rel(pool, id)); 221 id = rd->evr; 222 } 223 return l + strlen(pool->ss.stringspace + pool->ss.strings[id]); 224 } 225 226 static void 227 dep2strcpy(const Pool *pool, char *p, Id id, int oldrel) 228 { 229 while (ISRELDEP(id)) 230 { 231 Reldep *rd = GETRELDEP(pool, id); 232 if (oldrel == REL_AND || oldrel == REL_OR || oldrel == REL_WITH) 233 if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_WITH) 234 if (oldrel != rd->flags) 235 { 236 *p++ = '('; 237 dep2strcpy(pool, p, rd->name, rd->flags); 238 p += strlen(p); 239 strcpy(p, pool_id2rel(pool, id)); 240 p += strlen(p); 241 dep2strcpy(pool, p, rd->evr, rd->flags); 242 strcat(p, ")"); 243 return; 244 } 245 dep2strcpy(pool, p, rd->name, rd->flags); 246 p += strlen(p); 247 if (rd->flags == REL_NAMESPACE) 248 { 249 *p++ = '('; 250 dep2strcpy(pool, p, rd->evr, rd->flags); 251 strcat(p, ")"); 252 return; 253 } 254 if (rd->flags == REL_FILECONFLICT) 255 { 256 *p = 0; 257 return; 258 } 259 strcpy(p, pool_id2rel(pool, id)); 260 p += strlen(p); 261 id = rd->evr; 262 oldrel = rd->flags; 263 } 264 strcpy(p, pool->ss.stringspace + pool->ss.strings[id]); 265 } 266 267 const char * 268 pool_dep2str(Pool *pool, Id id) 269 { 270 char *p; 271 if (!ISRELDEP(id)) 272 return pool->ss.stringspace + pool->ss.strings[id]; 273 p = pool_alloctmpspace(pool, dep2strlen(pool, id) + 1); 274 dep2strcpy(pool, p, id, 0); 275 return p; 276 } 277 278 void 279 pool_shrink_strings(Pool *pool) 280 { 281 stringpool_shrink(&pool->ss); 282 } 283 284 void 285 pool_shrink_rels(Pool *pool) 286 { 287 pool->rels = solv_extend_resize(pool->rels, pool->nrels, sizeof(Reldep), REL_BLOCK); 288 } 289 290 /* free all hash tables */ 291 void 292 pool_freeidhashes(Pool *pool) 293 { 294 stringpool_freehash(&pool->ss); 295 pool->relhashtbl = solv_free(pool->relhashtbl); 296 pool->relhashmask = 0; 297 } 298 299 /* EOF */ 300