File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / hash.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:37:58 2012 UTC (12 years, 4 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_7_8, HEAD
libxml2

    1: /*
    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:  *
   17:  * Author: breese@users.sourceforge.net
   18:  */
   19: 
   20: #define IN_LIBXML
   21: #include "libxml.h"
   22: 
   23: #include <string.h>
   24: #include <libxml/parser.h>
   25: #include <libxml/hash.h>
   26: #include <libxml/xmlmemory.h>
   27: #include <libxml/xmlerror.h>
   28: #include <libxml/globals.h>
   29: 
   30: #define MAX_HASH_LEN 8
   31: 
   32: /* #define DEBUG_GROW */
   33: 
   34: /*
   35:  * A single entry in the hash table
   36:  */
   37: typedef struct _xmlHashEntry xmlHashEntry;
   38: typedef xmlHashEntry *xmlHashEntryPtr;
   39: struct _xmlHashEntry {
   40:     struct _xmlHashEntry *next;
   41:     xmlChar *name;
   42:     xmlChar *name2;
   43:     xmlChar *name3;
   44:     void *payload;
   45:     int valid;
   46: };
   47: 
   48: /*
   49:  * The entire hash table
   50:  */
   51: struct _xmlHashTable {
   52:     struct _xmlHashEntry *table;
   53:     int size;
   54:     int nbElems;
   55:     xmlDictPtr dict;
   56: };
   57: 
   58: /*
   59:  * xmlHashComputeKey:
   60:  * Calculate the hash key
   61:  */
   62: static unsigned long
   63: xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
   64: 	          const xmlChar *name2, const xmlChar *name3) {
   65:     unsigned long value = 0L;
   66:     char ch;
   67:     
   68:     if (name != NULL) {
   69: 	value += 30 * (*name);
   70: 	while ((ch = *name++) != 0) {
   71: 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
   72: 	}
   73:     }
   74:     if (name2 != NULL) {
   75: 	while ((ch = *name2++) != 0) {
   76: 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
   77: 	}
   78:     }
   79:     if (name3 != NULL) {
   80: 	while ((ch = *name3++) != 0) {
   81: 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
   82: 	}
   83:     }
   84:     return (value % table->size);
   85: }
   86: 
   87: static unsigned long
   88: xmlHashComputeQKey(xmlHashTablePtr table,
   89: 		   const xmlChar *prefix, const xmlChar *name,
   90: 		   const xmlChar *prefix2, const xmlChar *name2,
   91: 		   const xmlChar *prefix3, const xmlChar *name3) {
   92:     unsigned long value = 0L;
   93:     char ch;
   94:     
   95:     if (prefix != NULL)
   96: 	value += 30 * (*prefix);
   97:     else
   98: 	value += 30 * (*name);
   99: 
  100:     if (prefix != NULL) {
  101: 	while ((ch = *prefix++) != 0) {
  102: 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
  103: 	}
  104: 	value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
  105:     }
  106:     if (name != NULL) {
  107: 	while ((ch = *name++) != 0) {
  108: 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
  109: 	}
  110:     }
  111:     if (prefix2 != NULL) {
  112: 	while ((ch = *prefix2++) != 0) {
  113: 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
  114: 	}
  115: 	value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
  116:     }
  117:     if (name2 != NULL) {
  118: 	while ((ch = *name2++) != 0) {
  119: 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
  120: 	}
  121:     }
  122:     if (prefix3 != NULL) {
  123: 	while ((ch = *prefix3++) != 0) {
  124: 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
  125: 	}
  126: 	value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':');
  127:     }
  128:     if (name3 != NULL) {
  129: 	while ((ch = *name3++) != 0) {
  130: 	    value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
  131: 	}
  132:     }
  133:     return (value % table->size);
  134: }
  135: 
  136: /**
  137:  * xmlHashCreate:
  138:  * @size: the size of the hash table
  139:  *
  140:  * Create a new xmlHashTablePtr.
  141:  *
  142:  * Returns the newly created object, or NULL if an error occured.
  143:  */
  144: xmlHashTablePtr
  145: xmlHashCreate(int size) {
  146:     xmlHashTablePtr table;
  147:   
  148:     if (size <= 0)
  149:         size = 256;
  150:   
  151:     table = xmlMalloc(sizeof(xmlHashTable));
  152:     if (table) {
  153:         table->dict = NULL;
  154:         table->size = size;
  155: 	table->nbElems = 0;
  156:         table->table = xmlMalloc(size * sizeof(xmlHashEntry));
  157:         if (table->table) {
  158:   	    memset(table->table, 0, size * sizeof(xmlHashEntry));
  159:   	    return(table);
  160:         }
  161:         xmlFree(table);
  162:     }
  163:     return(NULL);
  164: }
  165: 
  166: /**
  167:  * xmlHashCreateDict:
  168:  * @size: the size of the hash table
  169:  * @dict: a dictionary to use for the hash
  170:  *
  171:  * Create a new xmlHashTablePtr which will use @dict as the internal dictionary
  172:  *
  173:  * Returns the newly created object, or NULL if an error occured.
  174:  */
  175: xmlHashTablePtr
  176: xmlHashCreateDict(int size, xmlDictPtr dict) {
  177:     xmlHashTablePtr table;
  178: 
  179:     table = xmlHashCreate(size);
  180:     if (table != NULL) {
  181:         table->dict = dict;
  182: 	xmlDictReference(dict);
  183:     }
  184:     return(table);
  185: }
  186: 
  187: /**
  188:  * xmlHashGrow:
  189:  * @table: the hash table
  190:  * @size: the new size of the hash table
  191:  *
  192:  * resize the hash table
  193:  *
  194:  * Returns 0 in case of success, -1 in case of failure
  195:  */
  196: static int
  197: xmlHashGrow(xmlHashTablePtr table, int size) {
  198:     unsigned long key;
  199:     int oldsize, i;
  200:     xmlHashEntryPtr iter, next;
  201:     struct _xmlHashEntry *oldtable;
  202: #ifdef DEBUG_GROW
  203:     unsigned long nbElem = 0;
  204: #endif
  205:   
  206:     if (table == NULL)
  207: 	return(-1);
  208:     if (size < 8)
  209:         return(-1);
  210:     if (size > 8 * 2048)
  211: 	return(-1);
  212: 
  213:     oldsize = table->size;
  214:     oldtable = table->table;
  215:     if (oldtable == NULL)
  216:         return(-1);
  217:   
  218:     table->table = xmlMalloc(size * sizeof(xmlHashEntry));
  219:     if (table->table == NULL) {
  220: 	table->table = oldtable;
  221: 	return(-1);
  222:     }
  223:     memset(table->table, 0, size * sizeof(xmlHashEntry));
  224:     table->size = size;
  225: 
  226:     /*	If the two loops are merged, there would be situations where
  227: 	a new entry needs to allocated and data copied into it from 
  228: 	the main table. So instead, we run through the array twice, first
  229: 	copying all the elements in the main array (where we can't get
  230: 	conflicts) and then the rest, so we only free (and don't allocate)
  231:     */
  232:     for (i = 0; i < oldsize; i++) {
  233: 	if (oldtable[i].valid == 0) 
  234: 	    continue;
  235: 	key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2,
  236: 				oldtable[i].name3);
  237: 	memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry));
  238: 	table->table[key].next = NULL;
  239:     }
  240: 
  241:     for (i = 0; i < oldsize; i++) {
  242: 	iter = oldtable[i].next;
  243: 	while (iter) {
  244: 	    next = iter->next;
  245: 
  246: 	    /*
  247: 	     * put back the entry in the new table
  248: 	     */
  249: 
  250: 	    key = xmlHashComputeKey(table, iter->name, iter->name2,
  251: 		                    iter->name3);
  252: 	    if (table->table[key].valid == 0) {
  253: 		memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry));
  254: 		table->table[key].next = NULL;
  255: 		xmlFree(iter);
  256: 	    } else {
  257: 	    	iter->next = table->table[key].next;
  258: 	    	table->table[key].next = iter;
  259: 	    }
  260: 
  261: #ifdef DEBUG_GROW
  262: 	    nbElem++;
  263: #endif
  264: 
  265: 	    iter = next;
  266: 	}
  267:     }
  268: 
  269:     xmlFree(oldtable);
  270: 
  271: #ifdef DEBUG_GROW
  272:     xmlGenericError(xmlGenericErrorContext,
  273: 	    "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
  274: #endif
  275: 
  276:     return(0);
  277: }
  278: 
  279: /**
  280:  * xmlHashFree:
  281:  * @table: the hash table
  282:  * @f:  the deallocator function for items in the hash
  283:  *
  284:  * Free the hash @table and its contents. The userdata is
  285:  * deallocated with @f if provided.
  286:  */
  287: void
  288: xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
  289:     int i;
  290:     xmlHashEntryPtr iter;
  291:     xmlHashEntryPtr next;
  292:     int inside_table = 0;
  293:     int nbElems;
  294: 
  295:     if (table == NULL)
  296: 	return;
  297:     if (table->table) {
  298: 	nbElems = table->nbElems;
  299: 	for(i = 0; (i < table->size) && (nbElems > 0); i++) {
  300: 	    iter = &(table->table[i]);
  301: 	    if (iter->valid == 0)
  302: 		continue;
  303: 	    inside_table = 1;
  304: 	    while (iter) {
  305: 		next = iter->next;
  306: 		if ((f != NULL) && (iter->payload != NULL))
  307: 		    f(iter->payload, iter->name);
  308: 		if (table->dict == NULL) {
  309: 		    if (iter->name)
  310: 			xmlFree(iter->name);
  311: 		    if (iter->name2)
  312: 			xmlFree(iter->name2);
  313: 		    if (iter->name3)
  314: 			xmlFree(iter->name3);
  315: 		}
  316: 		iter->payload = NULL;
  317: 		if (!inside_table)
  318: 		    xmlFree(iter);
  319: 		nbElems--;
  320: 		inside_table = 0;
  321: 		iter = next;
  322: 	    }
  323: 	}
  324: 	xmlFree(table->table);
  325:     }
  326:     if (table->dict)
  327:         xmlDictFree(table->dict);
  328:     xmlFree(table);
  329: }
  330: 
  331: /**
  332:  * xmlHashAddEntry:
  333:  * @table: the hash table
  334:  * @name: the name of the userdata
  335:  * @userdata: a pointer to the userdata
  336:  *
  337:  * Add the @userdata to the hash @table. This can later be retrieved
  338:  * by using the @name. Duplicate names generate errors.
  339:  *
  340:  * Returns 0 the addition succeeded and -1 in case of error.
  341:  */
  342: int
  343: xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
  344:     return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
  345: }
  346: 
  347: /**
  348:  * xmlHashAddEntry2:
  349:  * @table: the hash table
  350:  * @name: the name of the userdata
  351:  * @name2: a second name of the userdata
  352:  * @userdata: a pointer to the userdata
  353:  *
  354:  * Add the @userdata to the hash @table. This can later be retrieved
  355:  * by using the (@name, @name2) tuple. Duplicate tuples generate errors.
  356:  *
  357:  * Returns 0 the addition succeeded and -1 in case of error.
  358:  */
  359: int
  360: xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
  361: 	        const xmlChar *name2, void *userdata) {
  362:     return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
  363: }
  364: 
  365: /**
  366:  * xmlHashUpdateEntry:
  367:  * @table: the hash table
  368:  * @name: the name of the userdata
  369:  * @userdata: a pointer to the userdata
  370:  * @f: the deallocator function for replaced item (if any)
  371:  *
  372:  * Add the @userdata to the hash @table. This can later be retrieved
  373:  * by using the @name. Existing entry for this @name will be removed
  374:  * and freed with @f if found.
  375:  *
  376:  * Returns 0 the addition succeeded and -1 in case of error.
  377:  */
  378: int
  379: xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
  380: 	           void *userdata, xmlHashDeallocator f) {
  381:     return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
  382: }
  383: 
  384: /**
  385:  * xmlHashUpdateEntry2:
  386:  * @table: the hash table
  387:  * @name: the name of the userdata
  388:  * @name2: a second name of the userdata
  389:  * @userdata: a pointer to the userdata
  390:  * @f: the deallocator function for replaced item (if any)
  391:  *
  392:  * Add the @userdata to the hash @table. This can later be retrieved
  393:  * by using the (@name, @name2) tuple. Existing entry for this tuple will
  394:  * be removed and freed with @f if found.
  395:  *
  396:  * Returns 0 the addition succeeded and -1 in case of error.
  397:  */
  398: int
  399: xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
  400: 	           const xmlChar *name2, void *userdata,
  401: 		   xmlHashDeallocator f) {
  402:     return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
  403: }
  404: 
  405: /**
  406:  * xmlHashLookup:
  407:  * @table: the hash table
  408:  * @name: the name of the userdata
  409:  *
  410:  * Find the userdata specified by the @name.
  411:  *
  412:  * Returns the pointer to the userdata
  413:  */
  414: void *
  415: xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
  416:     return(xmlHashLookup3(table, name, NULL, NULL));
  417: }
  418: 
  419: /**
  420:  * xmlHashLookup2:
  421:  * @table: the hash table
  422:  * @name: the name of the userdata
  423:  * @name2: a second name of the userdata
  424:  *
  425:  * Find the userdata specified by the (@name, @name2) tuple.
  426:  *
  427:  * Returns the pointer to the userdata
  428:  */
  429: void *
  430: xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
  431: 	      const xmlChar *name2) {
  432:     return(xmlHashLookup3(table, name, name2, NULL));
  433: }
  434: 
  435: /**
  436:  * xmlHashQLookup:
  437:  * @table: the hash table
  438:  * @prefix: the prefix of the userdata
  439:  * @name: the name of the userdata
  440:  *
  441:  * Find the userdata specified by the QName @prefix:@name/@name.
  442:  *
  443:  * Returns the pointer to the userdata
  444:  */
  445: void *
  446: xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix,
  447:                const xmlChar *name) {
  448:     return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL));
  449: }
  450: 
  451: /**
  452:  * xmlHashQLookup2:
  453:  * @table: the hash table
  454:  * @prefix: the prefix of the userdata
  455:  * @name: the name of the userdata
  456:  * @prefix2: the second prefix of the userdata
  457:  * @name2: a second name of the userdata
  458:  *
  459:  * Find the userdata specified by the QNames tuple
  460:  *
  461:  * Returns the pointer to the userdata
  462:  */
  463: void *
  464: xmlHashQLookup2(xmlHashTablePtr table, const xmlChar *prefix,
  465:                 const xmlChar *name, const xmlChar *prefix2,
  466: 	        const xmlChar *name2) {
  467:     return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL));
  468: }
  469: 
  470: /**
  471:  * xmlHashAddEntry3:
  472:  * @table: the hash table
  473:  * @name: the name of the userdata
  474:  * @name2: a second name of the userdata
  475:  * @name3: a third name of the userdata
  476:  * @userdata: a pointer to the userdata
  477:  *
  478:  * Add the @userdata to the hash @table. This can later be retrieved
  479:  * by using the tuple (@name, @name2, @name3). Duplicate entries generate
  480:  * errors.
  481:  *
  482:  * Returns 0 the addition succeeded and -1 in case of error.
  483:  */
  484: int
  485: xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
  486: 	         const xmlChar *name2, const xmlChar *name3,
  487: 		 void *userdata) {
  488:     unsigned long key, len = 0;
  489:     xmlHashEntryPtr entry;
  490:     xmlHashEntryPtr insert;
  491: 
  492:     if ((table == NULL) || (name == NULL))
  493: 	return(-1);
  494: 
  495:     /*
  496:      * If using a dict internalize if needed
  497:      */
  498:     if (table->dict) {
  499:         if (!xmlDictOwns(table->dict, name)) {
  500: 	    name = xmlDictLookup(table->dict, name, -1);
  501: 	    if (name == NULL)
  502: 	        return(-1);
  503: 	}
  504:         if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
  505: 	    name2 = xmlDictLookup(table->dict, name2, -1);
  506: 	    if (name2 == NULL)
  507: 	        return(-1);
  508: 	}
  509:         if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
  510: 	    name3 = xmlDictLookup(table->dict, name3, -1);
  511: 	    if (name3 == NULL)
  512: 	        return(-1);
  513: 	}
  514:     }
  515: 
  516:     /*
  517:      * Check for duplicate and insertion location.
  518:      */
  519:     key = xmlHashComputeKey(table, name, name2, name3);
  520:     if (table->table[key].valid == 0) {
  521: 	insert = NULL;
  522:     } else {
  523:         if (table->dict) {
  524: 	    for (insert = &(table->table[key]); insert->next != NULL;
  525: 		 insert = insert->next) {
  526: 		if ((insert->name == name) &&
  527: 		    (insert->name2 == name2) &&
  528: 		    (insert->name3 == name3))
  529: 		    return(-1);
  530: 		len++;
  531: 	    }
  532: 	    if ((insert->name == name) &&
  533: 		(insert->name2 == name2) &&
  534: 		(insert->name3 == name3))
  535: 		return(-1);
  536: 	} else {
  537: 	    for (insert = &(table->table[key]); insert->next != NULL;
  538: 		 insert = insert->next) {
  539: 		if ((xmlStrEqual(insert->name, name)) &&
  540: 		    (xmlStrEqual(insert->name2, name2)) &&
  541: 		    (xmlStrEqual(insert->name3, name3)))
  542: 		    return(-1);
  543: 		len++;
  544: 	    }
  545: 	    if ((xmlStrEqual(insert->name, name)) &&
  546: 		(xmlStrEqual(insert->name2, name2)) &&
  547: 		(xmlStrEqual(insert->name3, name3)))
  548: 		return(-1);
  549: 	}
  550:     }
  551: 
  552:     if (insert == NULL) {
  553: 	entry = &(table->table[key]);
  554:     } else {
  555: 	entry = xmlMalloc(sizeof(xmlHashEntry));
  556: 	if (entry == NULL)
  557: 	     return(-1);
  558:     }
  559: 
  560:     if (table->dict != NULL) {
  561:         entry->name = (xmlChar *) name;
  562:         entry->name2 = (xmlChar *) name2;
  563:         entry->name3 = (xmlChar *) name3;
  564:     } else {
  565: 	entry->name = xmlStrdup(name);
  566: 	entry->name2 = xmlStrdup(name2);
  567: 	entry->name3 = xmlStrdup(name3);
  568:     }
  569:     entry->payload = userdata;
  570:     entry->next = NULL;
  571:     entry->valid = 1;
  572: 
  573: 
  574:     if (insert != NULL) 
  575: 	insert->next = entry;
  576: 
  577:     table->nbElems++;
  578: 
  579:     if (len > MAX_HASH_LEN)
  580: 	xmlHashGrow(table, MAX_HASH_LEN * table->size);
  581: 
  582:     return(0);
  583: }
  584: 
  585: /**
  586:  * xmlHashUpdateEntry3:
  587:  * @table: the hash table
  588:  * @name: the name of the userdata
  589:  * @name2: a second name of the userdata
  590:  * @name3: a third name of the userdata
  591:  * @userdata: a pointer to the userdata
  592:  * @f: the deallocator function for replaced item (if any)
  593:  *
  594:  * Add the @userdata to the hash @table. This can later be retrieved
  595:  * by using the tuple (@name, @name2, @name3). Existing entry for this tuple
  596:  * will be removed and freed with @f if found.
  597:  *
  598:  * Returns 0 the addition succeeded and -1 in case of error.
  599:  */
  600: int
  601: xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
  602: 	           const xmlChar *name2, const xmlChar *name3,
  603: 		   void *userdata, xmlHashDeallocator f) {
  604:     unsigned long key;
  605:     xmlHashEntryPtr entry;
  606:     xmlHashEntryPtr insert;
  607: 
  608:     if ((table == NULL) || name == NULL)
  609: 	return(-1);
  610: 
  611:     /*
  612:      * If using a dict internalize if needed
  613:      */
  614:     if (table->dict) {
  615:         if (!xmlDictOwns(table->dict, name)) {
  616: 	    name = xmlDictLookup(table->dict, name, -1);
  617: 	    if (name == NULL)
  618: 	        return(-1);
  619: 	}
  620:         if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) {
  621: 	    name2 = xmlDictLookup(table->dict, name2, -1);
  622: 	    if (name2 == NULL)
  623: 	        return(-1);
  624: 	}
  625:         if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) {
  626: 	    name3 = xmlDictLookup(table->dict, name3, -1);
  627: 	    if (name3 == NULL)
  628: 	        return(-1);
  629: 	}
  630:     }
  631: 
  632:     /*
  633:      * Check for duplicate and insertion location.
  634:      */
  635:     key = xmlHashComputeKey(table, name, name2, name3);
  636:     if (table->table[key].valid == 0) {
  637: 	insert = NULL;
  638:     } else {
  639:         if (table ->dict) {
  640: 	    for (insert = &(table->table[key]); insert->next != NULL;
  641: 		 insert = insert->next) {
  642: 		if ((insert->name == name) &&
  643: 		    (insert->name2 == name2) &&
  644: 		    (insert->name3 == name3)) {
  645: 		    if (f)
  646: 			f(insert->payload, insert->name);
  647: 		    insert->payload = userdata;
  648: 		    return(0);
  649: 		}
  650: 	    }
  651: 	    if ((insert->name == name) &&
  652: 		(insert->name2 == name2) &&
  653: 		(insert->name3 == name3)) {
  654: 		if (f)
  655: 		    f(insert->payload, insert->name);
  656: 		insert->payload = userdata;
  657: 		return(0);
  658: 	    }
  659: 	} else {
  660: 	    for (insert = &(table->table[key]); insert->next != NULL;
  661: 		 insert = insert->next) {
  662: 		if ((xmlStrEqual(insert->name, name)) &&
  663: 		    (xmlStrEqual(insert->name2, name2)) &&
  664: 		    (xmlStrEqual(insert->name3, name3))) {
  665: 		    if (f)
  666: 			f(insert->payload, insert->name);
  667: 		    insert->payload = userdata;
  668: 		    return(0);
  669: 		}
  670: 	    }
  671: 	    if ((xmlStrEqual(insert->name, name)) &&
  672: 		(xmlStrEqual(insert->name2, name2)) &&
  673: 		(xmlStrEqual(insert->name3, name3))) {
  674: 		if (f)
  675: 		    f(insert->payload, insert->name);
  676: 		insert->payload = userdata;
  677: 		return(0);
  678: 	    }
  679: 	}
  680:     }
  681: 
  682:     if (insert == NULL) {
  683: 	entry =  &(table->table[key]);
  684:     } else {
  685: 	entry = xmlMalloc(sizeof(xmlHashEntry));
  686: 	if (entry == NULL)
  687: 	     return(-1);
  688:     }
  689: 
  690:     if (table->dict != NULL) {
  691:         entry->name = (xmlChar *) name;
  692:         entry->name2 = (xmlChar *) name2;
  693:         entry->name3 = (xmlChar *) name3;
  694:     } else {
  695: 	entry->name = xmlStrdup(name);
  696: 	entry->name2 = xmlStrdup(name2);
  697: 	entry->name3 = xmlStrdup(name3);
  698:     }
  699:     entry->payload = userdata;
  700:     entry->next = NULL;
  701:     entry->valid = 1;
  702:     table->nbElems++;
  703: 
  704: 
  705:     if (insert != NULL) {
  706: 	insert->next = entry;
  707:     }
  708:     return(0);
  709: }
  710: 
  711: /**
  712:  * xmlHashLookup3:
  713:  * @table: the hash table
  714:  * @name: the name of the userdata
  715:  * @name2: a second name of the userdata
  716:  * @name3: a third name of the userdata
  717:  *
  718:  * Find the userdata specified by the (@name, @name2, @name3) tuple.
  719:  *
  720:  * Returns the a pointer to the userdata
  721:  */
  722: void *
  723: xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name, 
  724: 	       const xmlChar *name2, const xmlChar *name3) {
  725:     unsigned long key;
  726:     xmlHashEntryPtr entry;
  727: 
  728:     if (table == NULL)
  729: 	return(NULL);
  730:     if (name == NULL)
  731: 	return(NULL);
  732:     key = xmlHashComputeKey(table, name, name2, name3);
  733:     if (table->table[key].valid == 0)
  734: 	return(NULL);
  735:     if (table->dict) {
  736: 	for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
  737: 	    if ((entry->name == name) &&
  738: 		(entry->name2 == name2) &&
  739: 		(entry->name3 == name3))
  740: 		return(entry->payload);
  741: 	}
  742:     }
  743:     for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
  744: 	if ((xmlStrEqual(entry->name, name)) &&
  745: 	    (xmlStrEqual(entry->name2, name2)) &&
  746: 	    (xmlStrEqual(entry->name3, name3)))
  747: 	    return(entry->payload);
  748:     }
  749:     return(NULL);
  750: }
  751: 
  752: /**
  753:  * xmlHashQLookup3:
  754:  * @table: the hash table
  755:  * @prefix: the prefix of the userdata
  756:  * @name: the name of the userdata
  757:  * @prefix2: the second prefix of the userdata
  758:  * @name2: a second name of the userdata
  759:  * @prefix3: the third prefix of the userdata
  760:  * @name3: a third name of the userdata
  761:  *
  762:  * Find the userdata specified by the (@name, @name2, @name3) tuple.
  763:  *
  764:  * Returns the a pointer to the userdata
  765:  */
  766: void *
  767: xmlHashQLookup3(xmlHashTablePtr table,
  768:                 const xmlChar *prefix, const xmlChar *name,
  769: 		const xmlChar *prefix2, const xmlChar *name2,
  770: 		const xmlChar *prefix3, const xmlChar *name3) {
  771:     unsigned long key;
  772:     xmlHashEntryPtr entry;
  773: 
  774:     if (table == NULL)
  775: 	return(NULL);
  776:     if (name == NULL)
  777: 	return(NULL);
  778:     key = xmlHashComputeQKey(table, prefix, name, prefix2,
  779:                              name2, prefix3, name3);
  780:     if (table->table[key].valid == 0)
  781: 	return(NULL);
  782:     for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
  783: 	if ((xmlStrQEqual(prefix, name, entry->name)) &&
  784: 	    (xmlStrQEqual(prefix2, name2, entry->name2)) &&
  785: 	    (xmlStrQEqual(prefix3, name3, entry->name3)))
  786: 	    return(entry->payload);
  787:     }
  788:     return(NULL);
  789: }
  790: 
  791: typedef struct {
  792:     xmlHashScanner hashscanner;
  793:     void *data;
  794: } stubData;
  795: 
  796: static void 
  797: stubHashScannerFull (void *payload, void *data, const xmlChar *name, 
  798:                      const xmlChar *name2 ATTRIBUTE_UNUSED,
  799: 		     const xmlChar *name3 ATTRIBUTE_UNUSED) {
  800:     stubData *stubdata = (stubData *) data;
  801:     stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name);
  802: }                                  
  803:  
  804: /**
  805:  * xmlHashScan:
  806:  * @table: the hash table
  807:  * @f:  the scanner function for items in the hash
  808:  * @data:  extra data passed to f
  809:  *
  810:  * Scan the hash @table and applied @f to each value.
  811:  */
  812: void
  813: xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
  814:     stubData stubdata;
  815:     stubdata.data = data;
  816:     stubdata.hashscanner = f; 
  817:     xmlHashScanFull (table, stubHashScannerFull, &stubdata);
  818: }
  819: 
  820: /**
  821:  * xmlHashScanFull:
  822:  * @table: the hash table
  823:  * @f:  the scanner function for items in the hash
  824:  * @data:  extra data passed to f
  825:  *
  826:  * Scan the hash @table and applied @f to each value.
  827:  */
  828: void
  829: xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) {
  830:     int i, nb;
  831:     xmlHashEntryPtr iter;
  832:     xmlHashEntryPtr next;
  833: 
  834:     if (table == NULL)
  835: 	return;
  836:     if (f == NULL)
  837: 	return;
  838: 
  839:     if (table->table) {
  840: 	for(i = 0; i < table->size; i++) {
  841: 	    if (table->table[i].valid == 0) 
  842: 		continue;
  843: 	    iter = &(table->table[i]);
  844: 	    while (iter) {
  845: 		next = iter->next;
  846:                 nb = table->nbElems;
  847: 		if ((f != NULL) && (iter->payload != NULL))
  848: 		    f(iter->payload, data, iter->name,
  849: 		      iter->name2, iter->name3);
  850:                 if (nb != table->nbElems) {
  851:                     /* table was modified by the callback, be careful */
  852:                     if (iter == &(table->table[i])) {
  853:                         if (table->table[i].valid == 0)
  854:                             iter = NULL;
  855:                         if (table->table[i].next != next)
  856: 			    iter = &(table->table[i]);
  857:                     } else
  858: 		        iter = next;
  859:                 } else
  860: 		    iter = next;
  861: 	    }
  862: 	}
  863:     }
  864: }
  865: 
  866: /**
  867:  * xmlHashScan3:
  868:  * @table: the hash table
  869:  * @name: the name of the userdata or NULL
  870:  * @name2: a second name of the userdata or NULL
  871:  * @name3: a third name of the userdata or NULL
  872:  * @f:  the scanner function for items in the hash
  873:  * @data:  extra data passed to f
  874:  *
  875:  * Scan the hash @table and applied @f to each value matching
  876:  * (@name, @name2, @name3) tuple. If one of the names is null,
  877:  * the comparison is considered to match.
  878:  */
  879: void
  880: xmlHashScan3(xmlHashTablePtr table, const xmlChar *name, 
  881: 	     const xmlChar *name2, const xmlChar *name3,
  882: 	     xmlHashScanner f, void *data) {
  883:     xmlHashScanFull3 (table, name, name2, name3,
  884: 		      (xmlHashScannerFull) f, data);
  885: }
  886: 
  887: /**
  888:  * xmlHashScanFull3:
  889:  * @table: the hash table
  890:  * @name: the name of the userdata or NULL
  891:  * @name2: a second name of the userdata or NULL
  892:  * @name3: a third name of the userdata or NULL
  893:  * @f:  the scanner function for items in the hash
  894:  * @data:  extra data passed to f
  895:  *
  896:  * Scan the hash @table and applied @f to each value matching
  897:  * (@name, @name2, @name3) tuple. If one of the names is null,
  898:  * the comparison is considered to match.
  899:  */
  900: void
  901: xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name, 
  902: 		 const xmlChar *name2, const xmlChar *name3,
  903: 		 xmlHashScannerFull f, void *data) {
  904:     int i;
  905:     xmlHashEntryPtr iter;
  906:     xmlHashEntryPtr next;
  907: 
  908:     if (table == NULL)
  909: 	return;
  910:     if (f == NULL)
  911: 	return;
  912: 
  913:     if (table->table) {
  914: 	for(i = 0; i < table->size; i++) {
  915: 	    if (table->table[i].valid == 0)
  916: 		continue;
  917: 	    iter = &(table->table[i]);
  918: 	    while (iter) {
  919: 		next = iter->next;
  920: 		if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
  921: 		    ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
  922: 		    ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) &&
  923: 		    (iter->payload != NULL)) {
  924: 		    f(iter->payload, data, iter->name,
  925: 		      iter->name2, iter->name3);
  926: 		}
  927: 		iter = next;
  928: 	    }
  929: 	}
  930:     }
  931: }
  932: 
  933: /**
  934:  * xmlHashCopy:
  935:  * @table: the hash table
  936:  * @f:  the copier function for items in the hash
  937:  *
  938:  * Scan the hash @table and applied @f to each value.
  939:  *
  940:  * Returns the new table or NULL in case of error.
  941:  */
  942: xmlHashTablePtr
  943: xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
  944:     int i;
  945:     xmlHashEntryPtr iter;
  946:     xmlHashEntryPtr next;
  947:     xmlHashTablePtr ret;
  948: 
  949:     if (table == NULL)
  950: 	return(NULL);
  951:     if (f == NULL)
  952: 	return(NULL);
  953: 
  954:     ret = xmlHashCreate(table->size);
  955:     if (table->table) {
  956: 	for(i = 0; i < table->size; i++) {
  957: 	    if (table->table[i].valid == 0)
  958: 		continue;
  959: 	    iter = &(table->table[i]);
  960: 	    while (iter) {
  961: 		next = iter->next;
  962: 		xmlHashAddEntry3(ret, iter->name, iter->name2,
  963: 			         iter->name3, f(iter->payload, iter->name));
  964: 		iter = next;
  965: 	    }
  966: 	}
  967:     }
  968:     ret->nbElems = table->nbElems;
  969:     return(ret);
  970: }
  971: 
  972: /**
  973:  * xmlHashSize:
  974:  * @table: the hash table
  975:  *
  976:  * Query the number of elements installed in the hash @table.
  977:  *
  978:  * Returns the number of elements in the hash table or
  979:  * -1 in case of error
  980:  */
  981: int
  982: xmlHashSize(xmlHashTablePtr table) {
  983:     if (table == NULL)
  984: 	return(-1);
  985:     return(table->nbElems);
  986: }
  987: 
  988: /**
  989:  * xmlHashRemoveEntry:
  990:  * @table: the hash table
  991:  * @name: the name of the userdata
  992:  * @f: the deallocator function for removed item (if any)
  993:  *
  994:  * Find the userdata specified by the @name and remove
  995:  * it from the hash @table. Existing userdata for this tuple will be removed
  996:  * and freed with @f.
  997:  *
  998:  * Returns 0 if the removal succeeded and -1 in case of error or not found.
  999:  */
 1000: int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
 1001: 		       xmlHashDeallocator f) {
 1002:     return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
 1003: }
 1004: 
 1005: /**
 1006:  * xmlHashRemoveEntry2:
 1007:  * @table: the hash table
 1008:  * @name: the name of the userdata
 1009:  * @name2: a second name of the userdata
 1010:  * @f: the deallocator function for removed item (if any)
 1011:  *
 1012:  * Find the userdata specified by the (@name, @name2) tuple and remove
 1013:  * it from the hash @table. Existing userdata for this tuple will be removed
 1014:  * and freed with @f.
 1015:  *
 1016:  * Returns 0 if the removal succeeded and -1 in case of error or not found.
 1017:  */
 1018: int
 1019: xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
 1020: 			const xmlChar *name2, xmlHashDeallocator f) {
 1021:     return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
 1022: }
 1023: 
 1024: /**
 1025:  * xmlHashRemoveEntry3:
 1026:  * @table: the hash table
 1027:  * @name: the name of the userdata
 1028:  * @name2: a second name of the userdata
 1029:  * @name3: a third name of the userdata
 1030:  * @f: the deallocator function for removed item (if any)
 1031:  *
 1032:  * Find the userdata specified by the (@name, @name2, @name3) tuple and remove
 1033:  * it from the hash @table. Existing userdata for this tuple will be removed
 1034:  * and freed with @f.
 1035:  *
 1036:  * Returns 0 if the removal succeeded and -1 in case of error or not found.
 1037:  */
 1038: int
 1039: xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
 1040:     const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
 1041:     unsigned long key;
 1042:     xmlHashEntryPtr entry;
 1043:     xmlHashEntryPtr prev = NULL;
 1044: 
 1045:     if (table == NULL || name == NULL)
 1046:         return(-1);
 1047: 
 1048:     key = xmlHashComputeKey(table, name, name2, name3);
 1049:     if (table->table[key].valid == 0) {
 1050:         return(-1);
 1051:     } else {
 1052:         for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
 1053:             if (xmlStrEqual(entry->name, name) &&
 1054:                     xmlStrEqual(entry->name2, name2) &&
 1055:                     xmlStrEqual(entry->name3, name3)) {
 1056:                 if ((f != NULL) && (entry->payload != NULL))
 1057:                     f(entry->payload, entry->name);
 1058:                 entry->payload = NULL;
 1059: 		if (table->dict == NULL) {
 1060: 		    if(entry->name)
 1061: 			xmlFree(entry->name);
 1062: 		    if(entry->name2)
 1063: 			xmlFree(entry->name2);
 1064: 		    if(entry->name3)
 1065: 			xmlFree(entry->name3);
 1066: 		}
 1067:                 if(prev) {
 1068:                     prev->next = entry->next;
 1069: 		    xmlFree(entry);
 1070: 		} else {
 1071: 		    if (entry->next == NULL) {
 1072: 			entry->valid = 0;
 1073: 		    } else {
 1074: 			entry = entry->next;
 1075: 			memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry));
 1076: 			xmlFree(entry);
 1077: 		    }
 1078: 		}
 1079:                 table->nbElems--;
 1080:                 return(0);
 1081:             }
 1082:             prev = entry;
 1083:         }
 1084:         return(-1);
 1085:     }
 1086: }
 1087: 
 1088: #define bottom_hash
 1089: #include "elfgcchack.h"

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>