blob: ed10394b3c43f8c11bef12a429a3f61daee2209d [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * hash.c: chained hash tables
3 *
4 * Reference: Your favorite introductory book on algorithms
5 *
6 * Copyright (C) 2000 Bjorn Reese and Daniel Veillard.
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
13 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
14 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
15 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
16 *
Bjorn Reese70a9da52001-04-21 16:57:29 +000017 * Author: breese@users.sourceforge.net
Owen Taylor3473f882001-02-23 17:55:21 +000018 */
19
Bjorn Reese70a9da52001-04-21 16:57:29 +000020#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000021
22#include <string.h>
23#include <libxml/hash.h>
24#include <libxml/xmlmemory.h>
25#include <libxml/parser.h>
Daniel Veillarda10efa82001-04-18 13:09:01 +000026#include <libxml/xmlerror.h>
27
28#define MAX_HASH_LEN 8
29
30/* #define DEBUG_GROW */
Owen Taylor3473f882001-02-23 17:55:21 +000031
32/*
33 * A single entry in the hash table
34 */
35typedef struct _xmlHashEntry xmlHashEntry;
36typedef xmlHashEntry *xmlHashEntryPtr;
37struct _xmlHashEntry {
38 struct _xmlHashEntry *next;
39 xmlChar *name;
40 xmlChar *name2;
41 xmlChar *name3;
42 void *payload;
43};
44
45/*
46 * The entire hash table
47 */
48struct _xmlHashTable {
49 struct _xmlHashEntry **table;
50 int size;
51 int nbElems;
52};
53
54/*
55 * xmlHashComputeKey:
56 * Calculate the hash key
57 */
58static unsigned long
Daniel Veillarda10efa82001-04-18 13:09:01 +000059xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
60 const xmlChar *name2, const xmlChar *name3) {
Owen Taylor3473f882001-02-23 17:55:21 +000061 unsigned long value = 0L;
62 char ch;
63
Daniel Veillarda10efa82001-04-18 13:09:01 +000064 if (name != NULL) {
65 value += 30 * (*name);
66 while ((ch = *name++) != 0) {
67 /* value *= 31; */
68 value += (unsigned long)ch;
69 }
70 }
71 if (name2 != NULL) {
72 while ((ch = *name2++) != 0) {
73 /* value *= 31; */
74 value += (unsigned long)ch;
75 }
76 }
77 if (name3 != NULL) {
78 while ((ch = *name3++) != 0) {
79 /* value *= 31; */
80 value += (unsigned long)ch;
81 }
Owen Taylor3473f882001-02-23 17:55:21 +000082 }
83 return (value % table->size);
84}
85
86/**
87 * xmlHashCreate:
88 * @size: the size of the hash table
89 *
90 * Create a new xmlHashTablePtr.
91 *
92 * Returns the newly created object, or NULL if an error occured.
93 */
94xmlHashTablePtr
95xmlHashCreate(int size) {
96 xmlHashTablePtr table;
97
98 if (size <= 0)
99 size = 256;
100
101 table = xmlMalloc(sizeof(xmlHashTable));
102 if (table) {
103 table->size = size;
104 table->nbElems = 0;
105 table->table = xmlMalloc(size * sizeof(xmlHashEntry));
106 if (table->table) {
107 memset(table->table, 0, size * sizeof(xmlHashEntry));
108 return(table);
109 }
110 xmlFree(table);
111 }
112 return(NULL);
113}
114
115/**
Daniel Veillarda10efa82001-04-18 13:09:01 +0000116 * xmlHashGrow:
117 * @table: the hash table
118 * @size: the new size of the hash table
119 *
120 * resize the hash table
121 *
122 * Returns 0 in case of success, -1 in case of failure
123 */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000124static int
Daniel Veillarda10efa82001-04-18 13:09:01 +0000125xmlHashGrow(xmlHashTablePtr table, int size) {
126 unsigned long key;
127 int oldsize, i;
128 xmlHashEntryPtr iter, next;
129 struct _xmlHashEntry **oldtable;
130#ifdef DEBUG_GROW
131 unsigned long nbElem = 0;
132#endif
133
134 if (table == NULL)
135 return(-1);
136 if (size < 8)
137 return(-1);
138 if (size > 8 * 2048)
139 return(-1);
140
141 oldsize = table->size;
142 oldtable = table->table;
143 if (oldtable == NULL)
144 return(-1);
145
146 table->table = xmlMalloc(size * sizeof(xmlHashEntry));
147 if (table->table == NULL) {
148 table->table = oldtable;
149 return(-1);
150 }
151 memset(table->table, 0, size * sizeof(xmlHashEntry));
152 table->size = size;
153
154 for (i = 0; i < oldsize; i++) {
155 iter = oldtable[i];
156 while (iter) {
157 next = iter->next;
158
159 /*
160 * put back the entry in the new table
161 */
162
163 key = xmlHashComputeKey(table, iter->name, iter->name2,
164 iter->name3);
165 iter->next = table->table[key];
166 table->table[key] = iter;
167
168#ifdef DEBUG_GROW
169 nbElem++;
170#endif
171
172 iter = next;
173 }
174 }
175
176 xmlFree(oldtable);
177
178#ifdef DEBUG_GROW
179 xmlGenericError(xmlGenericErrorContext,
180 "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
181#endif
182
183 return(0);
184}
185
186/**
Owen Taylor3473f882001-02-23 17:55:21 +0000187 * xmlHashFree:
188 * @table: the hash table
189 * @f: the deallocator function for items in the hash
190 *
191 * Free the hash table and its contents. The userdata is
192 * deallocated with f if provided.
193 */
194void
195xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
196 int i;
197 xmlHashEntryPtr iter;
198 xmlHashEntryPtr next;
199
200 if (table == NULL)
201 return;
202 if (table->table) {
203 for(i = 0; i < table->size; i++) {
204 iter = table->table[i];
205 while (iter) {
206 next = iter->next;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000207 if (f)
208 f(iter->payload, iter->name);
Owen Taylor3473f882001-02-23 17:55:21 +0000209 if (iter->name)
210 xmlFree(iter->name);
211 if (iter->name2)
212 xmlFree(iter->name2);
213 if (iter->name3)
214 xmlFree(iter->name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000215 iter->payload = NULL;
216 xmlFree(iter);
217 iter = next;
218 }
219 table->table[i] = NULL;
220 }
221 xmlFree(table->table);
222 }
223 xmlFree(table);
224}
225
226/**
227 * xmlHashAddEntry:
228 * @table: the hash table
229 * @name: the name of the userdata
230 * @userdata: a pointer to the userdata
231 *
232 * Add the userdata to the hash table. This can later be retrieved
233 * by using the name. Duplicate names generate errors.
234 *
235 * Returns 0 the addition succeeded and -1 in case of error.
236 */
237int
238xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
239 return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
240}
241
242/**
243 * xmlHashAddEntry2:
244 * @table: the hash table
245 * @name: the name of the userdata
246 * @name2: a second name of the userdata
247 * @userdata: a pointer to the userdata
248 *
249 * Add the userdata to the hash table. This can later be retrieved
250 * by using the (name, name2) tuple. Duplicate tuples generate errors.
251 *
252 * Returns 0 the addition succeeded and -1 in case of error.
253 */
254int
255xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
256 const xmlChar *name2, void *userdata) {
257 return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
258}
259
260/**
261 * xmlHashUpdateEntry:
262 * @table: the hash table
263 * @name: the name of the userdata
264 * @userdata: a pointer to the userdata
265 * @f: the deallocator function for replaced item (if any)
266 *
267 * Add the userdata to the hash table. This can later be retrieved
268 * by using the name. Existing entry for this name will be removed
269 * and freed with @f if found.
270 *
271 * Returns 0 the addition succeeded and -1 in case of error.
272 */
273int
274xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
275 void *userdata, xmlHashDeallocator f) {
276 return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
277}
278
279/**
280 * xmlHashUpdateEntry2:
281 * @table: the hash table
282 * @name: the name of the userdata
283 * @name2: a second name of the userdata
284 * @userdata: a pointer to the userdata
285 * @f: the deallocator function for replaced item (if any)
286 *
287 * Add the userdata to the hash table. This can later be retrieved
288 * by using the (name, name2) tuple. Existing entry for this tuple will
289 * be removed and freed with @f if found.
290 *
291 * Returns 0 the addition succeeded and -1 in case of error.
292 */
293int
294xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
295 const xmlChar *name2, void *userdata,
296 xmlHashDeallocator f) {
297 return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
298}
299
300/**
301 * xmlHashLookup:
302 * @table: the hash table
303 * @name: the name of the userdata
304 *
305 * Find the userdata specified by the name.
306 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000307 * Returns the pointer to the userdata
Owen Taylor3473f882001-02-23 17:55:21 +0000308 */
309void *
310xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
311 return(xmlHashLookup3(table, name, NULL, NULL));
312}
313
314/**
315 * xmlHashLookup2:
316 * @table: the hash table
317 * @name: the name of the userdata
318 * @name2: a second name of the userdata
319 *
320 * Find the userdata specified by the (name, name2) tuple.
321 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000322 * Returns the pointer to the userdata
Owen Taylor3473f882001-02-23 17:55:21 +0000323 */
324void *
325xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
326 const xmlChar *name2) {
327 return(xmlHashLookup3(table, name, name2, NULL));
328}
329
330/**
331 * xmlHashAddEntry3:
332 * @table: the hash table
333 * @name: the name of the userdata
334 * @name2: a second name of the userdata
335 * @name3: a third name of the userdata
336 * @userdata: a pointer to the userdata
337 *
338 * Add the userdata to the hash table. This can later be retrieved
339 * by using the tuple (name, name2, name3). Duplicate entries generate
340 * errors.
341 *
342 * Returns 0 the addition succeeded and -1 in case of error.
343 */
344int
345xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
346 const xmlChar *name2, const xmlChar *name3,
347 void *userdata) {
Daniel Veillarda10efa82001-04-18 13:09:01 +0000348 unsigned long key, len = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000349 xmlHashEntryPtr entry;
350 xmlHashEntryPtr insert;
351
352 if ((table == NULL) || name == NULL)
353 return(-1);
354
355 /*
356 * Check for duplicate and insertion location.
357 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000358 key = xmlHashComputeKey(table, name, name2, name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000359 if (table->table[key] == NULL) {
360 insert = NULL;
361 } else {
362 for (insert = table->table[key]; insert->next != NULL;
363 insert = insert->next) {
364 if ((xmlStrEqual(insert->name, name)) &&
365 (xmlStrEqual(insert->name2, name2)) &&
366 (xmlStrEqual(insert->name3, name3)))
367 return(-1);
Daniel Veillarda10efa82001-04-18 13:09:01 +0000368 len++;
Owen Taylor3473f882001-02-23 17:55:21 +0000369 }
370 if ((xmlStrEqual(insert->name, name)) &&
371 (xmlStrEqual(insert->name2, name2)) &&
372 (xmlStrEqual(insert->name3, name3)))
373 return(-1);
374 }
375
376 entry = xmlMalloc(sizeof(xmlHashEntry));
377 if (entry == NULL)
378 return(-1);
379 entry->name = xmlStrdup(name);
380 entry->name2 = xmlStrdup(name2);
381 entry->name3 = xmlStrdup(name3);
382 entry->payload = userdata;
383 entry->next = NULL;
384
385
386 if (insert == NULL) {
387 table->table[key] = entry;
388 } else {
389 insert->next = entry;
390 }
391 table->nbElems++;
Daniel Veillarda10efa82001-04-18 13:09:01 +0000392
393 if (len > MAX_HASH_LEN)
394 xmlHashGrow(table, MAX_HASH_LEN * table->size);
395
Owen Taylor3473f882001-02-23 17:55:21 +0000396 return(0);
397}
398
399/**
400 * xmlHashUpdateEntry3:
401 * @table: the hash table
402 * @name: the name of the userdata
403 * @name2: a second name of the userdata
404 * @name3: a third name of the userdata
405 * @userdata: a pointer to the userdata
406 * @f: the deallocator function for replaced item (if any)
407 *
408 * Add the userdata to the hash table. This can later be retrieved
409 * by using the tuple (name, name2, name3). Existing entry for this tuple
410 * will be removed and freed with @f if found.
411 *
412 * Returns 0 the addition succeeded and -1 in case of error.
413 */
414int
415xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
416 const xmlChar *name2, const xmlChar *name3,
417 void *userdata, xmlHashDeallocator f) {
418 unsigned long key;
419 xmlHashEntryPtr entry;
420 xmlHashEntryPtr insert;
421
422 if ((table == NULL) || name == NULL)
423 return(-1);
424
425 /*
426 * Check for duplicate and insertion location.
427 */
Daniel Veillarda10efa82001-04-18 13:09:01 +0000428 key = xmlHashComputeKey(table, name, name2, name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000429 if (table->table[key] == NULL) {
430 insert = NULL;
431 } else {
432 for (insert = table->table[key]; insert->next != NULL;
433 insert = insert->next) {
434 if ((xmlStrEqual(insert->name, name)) &&
435 (xmlStrEqual(insert->name2, name2)) &&
436 (xmlStrEqual(insert->name3, name3))) {
437 if (f)
438 f(insert->payload, insert->name);
439 insert->payload = userdata;
440 return(0);
441 }
442 }
443 if ((xmlStrEqual(insert->name, name)) &&
444 (xmlStrEqual(insert->name2, name2)) &&
445 (xmlStrEqual(insert->name3, name3))) {
446 if (f)
447 f(insert->payload, insert->name);
448 insert->payload = userdata;
449 return(0);
450 }
451 }
452
453 entry = xmlMalloc(sizeof(xmlHashEntry));
454 if (entry == NULL)
455 return(-1);
456 entry->name = xmlStrdup(name);
457 entry->name2 = xmlStrdup(name2);
458 entry->name3 = xmlStrdup(name3);
459 entry->payload = userdata;
460 entry->next = NULL;
461 table->nbElems++;
462
463
464 if (insert == NULL) {
465 table->table[key] = entry;
466 } else {
467 insert->next = entry;
468 }
469 return(0);
470}
471
472/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000473 * xmlHashLookup3:
Owen Taylor3473f882001-02-23 17:55:21 +0000474 * @table: the hash table
475 * @name: the name of the userdata
476 * @name2: a second name of the userdata
477 * @name3: a third name of the userdata
478 *
479 * Find the userdata specified by the (name, name2, name3) tuple.
480 *
481 * Returns the a pointer to the userdata
482 */
483void *
484xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name,
485 const xmlChar *name2, const xmlChar *name3) {
486 unsigned long key;
487 xmlHashEntryPtr entry;
488
489 if (table == NULL)
490 return(NULL);
491 if (name == NULL)
492 return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +0000493 key = xmlHashComputeKey(table, name, name2, name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000494 for (entry = table->table[key]; entry != NULL; entry = entry->next) {
495 if ((xmlStrEqual(entry->name, name)) &&
496 (xmlStrEqual(entry->name2, name2)) &&
497 (xmlStrEqual(entry->name3, name3)))
498 return(entry->payload);
499 }
500 return(NULL);
501}
502
503/**
504 * xmlHashScan:
505 * @table: the hash table
506 * @f: the scanner function for items in the hash
507 * @data: extra data passed to f
508 *
509 * Scan the hash table and applied f to each value.
510 */
511void
512xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
Thomas Broyere8126242001-07-22 03:54:15 +0000513 xmlHashScanFull (table, (xmlHashScannerFull) f, data);
514}
515
516/**
517 * xmlHashScanFull:
518 * @table: the hash table
519 * @f: the scanner function for items in the hash
520 * @data: extra data passed to f
521 *
522 * Scan the hash table and applied f to each value.
523 */
524void
525xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
Owen Taylor3473f882001-02-23 17:55:21 +0000526 int i;
527 xmlHashEntryPtr iter;
528 xmlHashEntryPtr next;
529
530 if (table == NULL)
531 return;
532 if (f == NULL)
533 return;
534
535 if (table->table) {
536 for(i = 0; i < table->size; i++) {
537 iter = table->table[i];
538 while (iter) {
539 next = iter->next;
540 if (f)
Thomas Broyere8126242001-07-22 03:54:15 +0000541 f(iter->payload, data, iter->name,
542 iter->name2, iter->name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000543 iter = next;
544 }
545 }
546 }
547}
548
549/**
550 * xmlHashScan3:
551 * @table: the hash table
552 * @name: the name of the userdata or NULL
553 * @name2: a second name of the userdata or NULL
554 * @name3: a third name of the userdata or NULL
555 * @f: the scanner function for items in the hash
556 * @data: extra data passed to f
557 *
558 * Scan the hash table and applied f to each value matching
559 * (name, name2, name3) tuple. If one of the names is null,
560 * the comparison is considered to match.
561 */
562void
563xmlHashScan3(xmlHashTablePtr table, const xmlChar *name,
564 const xmlChar *name2, const xmlChar *name3,
565 xmlHashScanner f, void *data) {
Thomas Broyere8126242001-07-22 03:54:15 +0000566 xmlHashScanFull3 (table, name, name2, name3,
567 (xmlHashScannerFull) f, data);
568}
569
570/**
571 * xmlHashScanFull3:
572 * @table: the hash table
573 * @name: the name of the userdata or NULL
574 * @name2: a second name of the userdata or NULL
575 * @name3: a third name of the userdata or NULL
576 * @f: the scanner function for items in the hash
577 * @data: extra data passed to f
578 *
579 * Scan the hash table and applied f to each value matching
580 * (name, name2, name3) tuple. If one of the names is null,
581 * the comparison is considered to match.
582 */
583void
584xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name,
585 const xmlChar *name2, const xmlChar *name3,
586 xmlHashScannerFull f, void *data) {
Owen Taylor3473f882001-02-23 17:55:21 +0000587 int i;
588 xmlHashEntryPtr iter;
589 xmlHashEntryPtr next;
590
591 if (table == NULL)
592 return;
593 if (f == NULL)
594 return;
595
596 if (table->table) {
597 for(i = 0; i < table->size; i++) {
598 iter = table->table[i];
599 while (iter) {
600 next = iter->next;
601 if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
602 ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
603 ((name3 == NULL) || (xmlStrEqual(name3, iter->name3)))) {
Thomas Broyere8126242001-07-22 03:54:15 +0000604 f(iter->payload, data, iter->name,
605 iter->name2, iter->name3);
Owen Taylor3473f882001-02-23 17:55:21 +0000606 }
607 iter = next;
608 }
609 }
610 }
611}
612
613/**
614 * xmlHashCopy:
615 * @table: the hash table
616 * @f: the copier function for items in the hash
617 *
618 * Scan the hash table and applied f to each value.
619 *
620 * Returns the new table or NULL in case of error.
621 */
622xmlHashTablePtr
623xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
624 int i;
625 xmlHashEntryPtr iter;
626 xmlHashEntryPtr next;
627 xmlHashTablePtr ret;
628
629 if (table == NULL)
630 return(NULL);
631 if (f == NULL)
632 return(NULL);
633
634 ret = xmlHashCreate(table->size);
635 if (table->table) {
636 for(i = 0; i < table->size; i++) {
637 iter = table->table[i];
638 while (iter) {
639 next = iter->next;
640 xmlHashAddEntry3(ret, iter->name, iter->name2,
641 iter->name3, f(iter->payload, iter->name));
642 iter = next;
643 }
644 }
645 }
646 ret->nbElems = table->nbElems;
647 return(ret);
648}
649
650/**
651 * xmlHashSize:
652 * @table: the hash table
653 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +0000654 * Query the number of element installed in the hash table.
655 *
Owen Taylor3473f882001-02-23 17:55:21 +0000656 * Returns the number of elements in the hash table or
657 * -1 in case of error
658 */
659int
660xmlHashSize(xmlHashTablePtr table) {
661 if (table == NULL)
662 return(-1);
663 return(table->nbElems);
664}
665
666/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +0000667 * xmlHashRemoveEntry:
Owen Taylor3473f882001-02-23 17:55:21 +0000668 * @table: the hash table
669 * @name: the name of the userdata
670 * @f: the deallocator function for removed item (if any)
671 *
672 * Find the userdata specified by the (name, name2, name3) tuple and remove
673 * it from the hash table. Existing userdata for this tuple will be removed
674 * and freed with @f.
675 *
676 * Returns 0 if the removal succeeded and -1 in case of error or not found.
677 */
678int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +0000679 xmlHashDeallocator f) {
680 return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
Owen Taylor3473f882001-02-23 17:55:21 +0000681}
682
683/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +0000684 * xmlHashRemoveEntry2:
Owen Taylor3473f882001-02-23 17:55:21 +0000685 * @table: the hash table
686 * @name: the name of the userdata
687 * @name2: a second name of the userdata
688 * @f: the deallocator function for removed item (if any)
689 *
690 * Find the userdata specified by the (name, name2, name3) tuple and remove
691 * it from the hash table. Existing userdata for this tuple will be removed
692 * and freed with @f.
693 *
694 * Returns 0 if the removal succeeded and -1 in case of error or not found.
695 */
696int xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +0000697 const xmlChar *name2, xmlHashDeallocator f) {
698 return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
Owen Taylor3473f882001-02-23 17:55:21 +0000699}
700
701/**
Daniel Veillardf69bb4b2001-05-19 13:24:56 +0000702 * xmlHashRemoveEntry3
Owen Taylor3473f882001-02-23 17:55:21 +0000703 * @table: the hash table
704 * @name: the name of the userdata
705 * @name2: a second name of the userdata
706 * @name3: a third name of the userdata
707 * @f: the deallocator function for removed item (if any)
708 *
709 * Find the userdata specified by the (name, name2, name3) tuple and remove
710 * it from the hash table. Existing userdata for this tuple will be removed
711 * and freed with @f.
712 *
713 * Returns 0 if the removal succeeded and -1 in case of error or not found.
714 */
715int xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
Daniel Veillarda10efa82001-04-18 13:09:01 +0000716 const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
717 unsigned long key;
718 xmlHashEntryPtr entry;
719 xmlHashEntryPtr prev = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000720
Daniel Veillarda10efa82001-04-18 13:09:01 +0000721 if (table == NULL || name == NULL)
722 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +0000723
Daniel Veillarda10efa82001-04-18 13:09:01 +0000724 key = xmlHashComputeKey(table, name, name2, name3);
725 if (table->table[key] == NULL) {
726 return(-1);
727 } else {
728 for (entry = table->table[key]; entry != NULL; entry = entry->next) {
729 if (xmlStrEqual(entry->name, name) &&
730 xmlStrEqual(entry->name2, name2) &&
731 xmlStrEqual(entry->name3, name3)) {
732 if(f)
733 f(entry->payload, entry->name);
734 entry->payload = NULL;
735 if(entry->name)
736 xmlFree(entry->name);
737 if(entry->name2)
738 xmlFree(entry->name2);
739 if(entry->name3)
740 xmlFree(entry->name3);
741 if(prev)
742 prev->next = entry->next;
743 else
744 table->table[key] = entry->next;
745 xmlFree(entry);
746 table->nbElems--;
747 return(0);
748 }
749 prev = entry;
750 }
751 return(-1);
752 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000753}
754