| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | |
|---|
| 22 | |
|---|
| 23 | #include "polipo.h" |
|---|
| 24 | |
|---|
| 25 | static AtomPtr *atomHashTable; |
|---|
| 26 | int used_atoms; |
|---|
| 27 | |
|---|
| 28 | void |
|---|
| 29 | initAtoms() |
|---|
| 30 | { |
|---|
| 31 | atomHashTable = calloc((1 << LOG2_ATOM_HASH_TABLE_SIZE), |
|---|
| 32 | sizeof(AtomPtr)); |
|---|
| 33 | |
|---|
| 34 | if(atomHashTable == NULL) { |
|---|
| 35 | do_log(L_ERROR, "Couldn't allocate atom hash table.\n"); |
|---|
| 36 | exit(1); |
|---|
| 37 | } |
|---|
| 38 | used_atoms = 0; |
|---|
| 39 | } |
|---|
| 40 | |
|---|
| 41 | AtomPtr |
|---|
| 42 | internAtomN(const char *string, int n) |
|---|
| 43 | { |
|---|
| 44 | AtomPtr atom; |
|---|
| 45 | int h; |
|---|
| 46 | |
|---|
| 47 | if(n < 0 || n >= (1 << (8 * sizeof(unsigned short)))) |
|---|
| 48 | return NULL; |
|---|
| 49 | |
|---|
| 50 | h = hash(0, string, n, LOG2_ATOM_HASH_TABLE_SIZE); |
|---|
| 51 | atom = atomHashTable[h]; |
|---|
| 52 | while(atom) { |
|---|
| 53 | if(atom->length == n && |
|---|
| 54 | (n == 0 || memcmp(atom->string, string, n) == 0)) |
|---|
| 55 | break; |
|---|
| 56 | atom = atom->next; |
|---|
| 57 | } |
|---|
| 58 | |
|---|
| 59 | if(!atom) { |
|---|
| 60 | atom = malloc(sizeof(AtomRec) - 1 + n + 1); |
|---|
| 61 | if(atom == NULL) { |
|---|
| 62 | return NULL; |
|---|
| 63 | } |
|---|
| 64 | atom->refcount = 0; |
|---|
| 65 | atom->length = n; |
|---|
| 66 | |
|---|
| 67 | |
|---|
| 68 | |
|---|
| 69 | memcpy(atom->string, string, n); |
|---|
| 70 | atom->string[n] = '\0'; |
|---|
| 71 | atom->next = atomHashTable[h]; |
|---|
| 72 | atomHashTable[h] = atom; |
|---|
| 73 | used_atoms++; |
|---|
| 74 | } |
|---|
| 75 | do_log(D_ATOM_REFCOUNT, "A 0x%lx %d++\n", |
|---|
| 76 | (unsigned long)atom, atom->refcount); |
|---|
| 77 | atom->refcount++; |
|---|
| 78 | return atom; |
|---|
| 79 | } |
|---|
| 80 | |
|---|
| 81 | AtomPtr |
|---|
| 82 | internAtom(const char *string) |
|---|
| 83 | { |
|---|
| 84 | return internAtomN(string, strlen(string)); |
|---|
| 85 | } |
|---|
| 86 | |
|---|
| 87 | AtomPtr |
|---|
| 88 | atomCat(AtomPtr atom, const char *string) |
|---|
| 89 | { |
|---|
| 90 | char buf[128]; |
|---|
| 91 | char *s = buf; |
|---|
| 92 | AtomPtr newAtom; |
|---|
| 93 | int n = strlen(string); |
|---|
| 94 | if(atom->length + n > 128) { |
|---|
| 95 | s = malloc(atom->length + n + 1); |
|---|
| 96 | if(s == NULL) |
|---|
| 97 | return NULL; |
|---|
| 98 | } |
|---|
| 99 | memcpy(s, atom->string, atom->length); |
|---|
| 100 | memcpy(s + atom->length, string, n); |
|---|
| 101 | newAtom = internAtomN(s, atom->length + n); |
|---|
| 102 | if(s != buf) free(s); |
|---|
| 103 | return newAtom; |
|---|
| 104 | } |
|---|
| 105 | |
|---|
| 106 | int |
|---|
| 107 | atomSplit(AtomPtr atom, char c, AtomPtr *return1, AtomPtr *return2) |
|---|
| 108 | { |
|---|
| 109 | char *p; |
|---|
| 110 | AtomPtr atom1, atom2; |
|---|
| 111 | p = memchr(atom->string, c, atom->length); |
|---|
| 112 | if(p == NULL) |
|---|
| 113 | return 0; |
|---|
| 114 | atom1 = internAtomN(atom->string, p - atom->string); |
|---|
| 115 | if(atom1 == NULL) |
|---|
| 116 | return -ENOMEM; |
|---|
| 117 | atom2 = internAtomN(p + 1, atom->length - (p + 1 - atom->string)); |
|---|
| 118 | if(atom2 == NULL) { |
|---|
| 119 | releaseAtom(atom1); |
|---|
| 120 | return -ENOMEM; |
|---|
| 121 | } |
|---|
| 122 | *return1 = atom1; |
|---|
| 123 | *return2 = atom2; |
|---|
| 124 | return 1; |
|---|
| 125 | } |
|---|
| 126 | |
|---|
| 127 | AtomPtr |
|---|
| 128 | internAtomLowerN(const char *string, int n) |
|---|
| 129 | { |
|---|
| 130 | char *s; |
|---|
| 131 | char buf[100]; |
|---|
| 132 | AtomPtr atom; |
|---|
| 133 | |
|---|
| 134 | if(n < 0 || n >= 50000) |
|---|
| 135 | return NULL; |
|---|
| 136 | |
|---|
| 137 | if(n < 100) { |
|---|
| 138 | s = buf; |
|---|
| 139 | } else { |
|---|
| 140 | s = malloc(n); |
|---|
| 141 | if(s == NULL) |
|---|
| 142 | return NULL; |
|---|
| 143 | } |
|---|
| 144 | |
|---|
| 145 | lwrcpy(s, string, n); |
|---|
| 146 | atom = internAtomN(s, n); |
|---|
| 147 | if(s != buf) free(s); |
|---|
| 148 | return atom; |
|---|
| 149 | } |
|---|
| 150 | |
|---|
| 151 | AtomPtr |
|---|
| 152 | retainAtom(AtomPtr atom) |
|---|
| 153 | { |
|---|
| 154 | if(atom == NULL) |
|---|
| 155 | return NULL; |
|---|
| 156 | |
|---|
| 157 | do_log(D_ATOM_REFCOUNT, "A 0x%lx %d++\n", |
|---|
| 158 | (unsigned long)atom, atom->refcount); |
|---|
| 159 | assert(atom->refcount >= 1 && atom->refcount < 50000); |
|---|
| 160 | atom->refcount++; |
|---|
| 161 | return atom; |
|---|
| 162 | } |
|---|
| 163 | |
|---|
| 164 | void |
|---|
| 165 | releaseAtom(AtomPtr atom) |
|---|
| 166 | { |
|---|
| 167 | if(atom == NULL) |
|---|
| 168 | return; |
|---|
| 169 | |
|---|
| 170 | do_log(D_ATOM_REFCOUNT, "A 0x%lx %d--\n", |
|---|
| 171 | (unsigned long)atom, atom->refcount); |
|---|
| 172 | assert(atom->refcount >= 1 && atom->refcount < 50000); |
|---|
| 173 | |
|---|
| 174 | atom->refcount--; |
|---|
| 175 | |
|---|
| 176 | if(atom->refcount == 0) { |
|---|
| 177 | int h = hash(0, atom->string, atom->length, LOG2_ATOM_HASH_TABLE_SIZE); |
|---|
| 178 | assert(atomHashTable[h] != NULL); |
|---|
| 179 | |
|---|
| 180 | if(atom == atomHashTable[h]) { |
|---|
| 181 | atomHashTable[h] = atom->next; |
|---|
| 182 | free(atom); |
|---|
| 183 | } else { |
|---|
| 184 | AtomPtr previous = atomHashTable[h]; |
|---|
| 185 | while(previous->next) { |
|---|
| 186 | if(previous->next == atom) |
|---|
| 187 | break; |
|---|
| 188 | previous = previous->next; |
|---|
| 189 | } |
|---|
| 190 | assert(previous->next != NULL); |
|---|
| 191 | previous->next = atom->next; |
|---|
| 192 | free(atom); |
|---|
| 193 | } |
|---|
| 194 | used_atoms--; |
|---|
| 195 | } |
|---|
| 196 | } |
|---|
| 197 | |
|---|
| 198 | AtomPtr |
|---|
| 199 | internAtomF(const char *format, ...) |
|---|
| 200 | { |
|---|
| 201 | char *s; |
|---|
| 202 | char buf[150]; |
|---|
| 203 | int n; |
|---|
| 204 | va_list args; |
|---|
| 205 | AtomPtr atom = NULL; |
|---|
| 206 | |
|---|
| 207 | va_start(args, format); |
|---|
| 208 | n = vsnprintf(buf, 150, format, args); |
|---|
| 209 | va_end(args); |
|---|
| 210 | if(n >= 0 && n < 150) { |
|---|
| 211 | atom = internAtomN(buf, n); |
|---|
| 212 | } else { |
|---|
| 213 | va_start(args, format); |
|---|
| 214 | s = vsprintf_a(format, args); |
|---|
| 215 | va_end(args); |
|---|
| 216 | if(s != NULL) { |
|---|
| 217 | atom = internAtom(s); |
|---|
| 218 | free(s); |
|---|
| 219 | } |
|---|
| 220 | } |
|---|
| 221 | return atom; |
|---|
| 222 | } |
|---|
| 223 | |
|---|
| 224 | static AtomPtr |
|---|
| 225 | internAtomErrorV(int e, const char *f, va_list args) |
|---|
| 226 | { |
|---|
| 227 | |
|---|
| 228 | char *es = pstrerror(e); |
|---|
| 229 | AtomPtr atom; |
|---|
| 230 | char *s1, *s2; |
|---|
| 231 | int n, rc; |
|---|
| 232 | |
|---|
| 233 | if(f) { |
|---|
| 234 | s1 = vsprintf_a(f, args); |
|---|
| 235 | if(s1 == NULL) |
|---|
| 236 | return NULL; |
|---|
| 237 | n = strlen(s1); |
|---|
| 238 | } else { |
|---|
| 239 | s1 = NULL; |
|---|
| 240 | n = 0; |
|---|
| 241 | } |
|---|
| 242 | |
|---|
| 243 | s2 = malloc(n + 70); |
|---|
| 244 | if(s2 == NULL) { |
|---|
| 245 | free(s1); |
|---|
| 246 | return NULL; |
|---|
| 247 | } |
|---|
| 248 | if(s1) { |
|---|
| 249 | strcpy(s2, s1); |
|---|
| 250 | free(s1); |
|---|
| 251 | } |
|---|
| 252 | |
|---|
| 253 | rc = snprintf(s2 + n, 69, f ? ": %s" : "%s", es); |
|---|
| 254 | if(rc < 0 || rc >= 69) { |
|---|
| 255 | free(s2); |
|---|
| 256 | return NULL; |
|---|
| 257 | } |
|---|
| 258 | |
|---|
| 259 | atom = internAtomN(s2, n + rc); |
|---|
| 260 | free(s2); |
|---|
| 261 | return atom; |
|---|
| 262 | } |
|---|
| 263 | |
|---|
| 264 | AtomPtr |
|---|
| 265 | internAtomError(int e, const char *f, ...) |
|---|
| 266 | { |
|---|
| 267 | AtomPtr atom; |
|---|
| 268 | va_list args; |
|---|
| 269 | va_start(args, f); |
|---|
| 270 | atom = internAtomErrorV(e, f, args); |
|---|
| 271 | va_end(args); |
|---|
| 272 | return atom; |
|---|
| 273 | } |
|---|
| 274 | |
|---|
| 275 | char * |
|---|
| 276 | atomString(AtomPtr atom) |
|---|
| 277 | { |
|---|
| 278 | if(atom) |
|---|
| 279 | return atom->string; |
|---|
| 280 | else |
|---|
| 281 | return "(null)"; |
|---|
| 282 | } |
|---|
| 283 | |
|---|
| 284 | AtomListPtr |
|---|
| 285 | makeAtomList(AtomPtr *atoms, int n) |
|---|
| 286 | { |
|---|
| 287 | AtomListPtr list; |
|---|
| 288 | list = malloc(sizeof(AtomListRec)); |
|---|
| 289 | if(list == NULL) return NULL; |
|---|
| 290 | list->length = 0; |
|---|
| 291 | list->size = 0; |
|---|
| 292 | list->list = NULL; |
|---|
| 293 | if(n > 0) { |
|---|
| 294 | int i; |
|---|
| 295 | list->list = malloc(n * sizeof(AtomPtr)); |
|---|
| 296 | if(list->list == NULL) { |
|---|
| 297 | free(list); |
|---|
| 298 | return NULL; |
|---|
| 299 | } |
|---|
| 300 | list->size = n; |
|---|
| 301 | for(i = 0; i < n; i++) |
|---|
| 302 | list->list[i] = atoms[i]; |
|---|
| 303 | list->length = n; |
|---|
| 304 | } |
|---|
| 305 | return list; |
|---|
| 306 | } |
|---|
| 307 | |
|---|
| 308 | void |
|---|
| 309 | destroyAtomList(AtomListPtr list) |
|---|
| 310 | { |
|---|
| 311 | int i; |
|---|
| 312 | if(list->list) { |
|---|
| 313 | for(i = 0; i < list->length; i++) |
|---|
| 314 | releaseAtom(list->list[i]); |
|---|
| 315 | list->length = 0; |
|---|
| 316 | free(list->list); |
|---|
| 317 | list->list = NULL; |
|---|
| 318 | list->size = 0; |
|---|
| 319 | } |
|---|
| 320 | assert(list->size == 0); |
|---|
| 321 | free(list); |
|---|
| 322 | } |
|---|
| 323 | |
|---|
| 324 | int |
|---|
| 325 | atomListMember(AtomPtr atom, AtomListPtr list) |
|---|
| 326 | { |
|---|
| 327 | int i; |
|---|
| 328 | for(i = 0; i < list->length; i++) { |
|---|
| 329 | if(atom == list->list[i]) |
|---|
| 330 | return 1; |
|---|
| 331 | } |
|---|
| 332 | return 0; |
|---|
| 333 | } |
|---|
| 334 | |
|---|
| 335 | void |
|---|
| 336 | atomListCons(AtomPtr atom, AtomListPtr list) |
|---|
| 337 | { |
|---|
| 338 | if(list->list == NULL) { |
|---|
| 339 | assert(list->size == 0); |
|---|
| 340 | list->list = malloc(5 * sizeof(AtomPtr)); |
|---|
| 341 | if(list->list == NULL) { |
|---|
| 342 | do_log(L_ERROR, "Couldn't allocate AtomList\n"); |
|---|
| 343 | return; |
|---|
| 344 | } |
|---|
| 345 | list->size = 5; |
|---|
| 346 | } |
|---|
| 347 | if(list->size <= list->length) { |
|---|
| 348 | AtomPtr *new_list; |
|---|
| 349 | int n = (2 * list->length + 1); |
|---|
| 350 | new_list = realloc(list->list, n * sizeof(AtomPtr)); |
|---|
| 351 | if(new_list == NULL) { |
|---|
| 352 | do_log(L_ERROR, "Couldn't realloc AtomList\n"); |
|---|
| 353 | return; |
|---|
| 354 | } |
|---|
| 355 | list->list = new_list; |
|---|
| 356 | list->size = n; |
|---|
| 357 | } |
|---|
| 358 | list->list[list->length] = atom; |
|---|
| 359 | list->length++; |
|---|
| 360 | } |
|---|