Annotation of embedaddon/libxml2/hash.c, revision 1.1

1.1     ! misho       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>