Annotation of embedaddon/quagga/isisd/dict.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Dictionary Abstract Data Type
        !             3:  * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net>
        !             4:  *
        !             5:  * Free Software License:
        !             6:  *
        !             7:  * All rights are reserved by the author, with the following exceptions:
        !             8:  * Permission is granted to freely reproduce and distribute this software,
        !             9:  * possibly in exchange for a fee, provided that this copyright notice appears
        !            10:  * intact. Permission is also granted to adapt this software to produce
        !            11:  * derivative works, as long as the modified versions carry this copyright
        !            12:  * notice and additional notices stating that the work has been modified.
        !            13:  * This source code may be translated into executable form and incorporated
        !            14:  * into proprietary software; there is no requirement for such software to
        !            15:  * contain a copyright notice related to this source.
        !            16:  */
        !            17: 
        !            18: #include <stdlib.h>
        !            19: #include <stddef.h>
        !            20: #include "zebra.h"
        !            21: #include "zassert.h"
        !            22: #define DICT_IMPLEMENTATION
        !            23: #include "dict.h"
        !            24: 
        !            25: #ifdef KAZLIB_RCSID
        !            26: static const char rcsid[] = "Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz";
        !            27: #endif
        !            28: 
        !            29: /*
        !            30:  * These macros provide short convenient names for structure members,
        !            31:  * which are embellished with dict_ prefixes so that they are
        !            32:  * properly confined to the documented namespace. It's legal for a 
        !            33:  * program which uses dict to define, for instance, a macro called ``parent''.
        !            34:  * Such a macro would interfere with the dnode_t struct definition.
        !            35:  * In general, highly portable and reusable C modules which expose their
        !            36:  * structures need to confine structure member names to well-defined spaces.
        !            37:  * The resulting identifiers aren't necessarily convenient to use, nor
        !            38:  * readable, in the implementation, however!
        !            39:  */
        !            40: 
        !            41: #define left dict_left
        !            42: #define right dict_right
        !            43: #define parent dict_parent
        !            44: #define color dict_color
        !            45: #define key dict_key
        !            46: #define data dict_data
        !            47: 
        !            48: #define nilnode dict_nilnode
        !            49: #define nodecount dict_nodecount
        !            50: #define maxcount dict_maxcount
        !            51: #define compare dict_compare
        !            52: #define allocnode dict_allocnode
        !            53: #define freenode dict_freenode
        !            54: #define context dict_context
        !            55: #define dupes dict_dupes
        !            56: 
        !            57: #define dictptr dict_dictptr
        !            58: 
        !            59: #define dict_root(D) ((D)->nilnode.left)
        !            60: #define dict_nil(D) (&(D)->nilnode)
        !            61: #define DICT_DEPTH_MAX 64
        !            62: 
        !            63: static dnode_t *dnode_alloc(void *context);
        !            64: static void dnode_free(dnode_t *node, void *context);
        !            65: 
        !            66: /*
        !            67:  * Perform a ``left rotation'' adjustment on the tree.  The given node P and
        !            68:  * its right child C are rearranged so that the P instead becomes the left
        !            69:  * child of C.   The left subtree of C is inherited as the new right subtree
        !            70:  * for P.  The ordering of the keys within the tree is thus preserved.
        !            71:  */
        !            72: 
        !            73: static void rotate_left(dnode_t *upper)
        !            74: {
        !            75:     dnode_t *lower, *lowleft, *upparent;
        !            76: 
        !            77:     lower = upper->right;
        !            78:     upper->right = lowleft = lower->left;
        !            79:     lowleft->parent = upper;
        !            80: 
        !            81:     lower->parent = upparent = upper->parent;
        !            82: 
        !            83:     /* don't need to check for root node here because root->parent is
        !            84:        the sentinel nil node, and root->parent->left points back to root */
        !            85: 
        !            86:     if (upper == upparent->left) {
        !            87:        upparent->left = lower;
        !            88:     } else {
        !            89:        assert (upper == upparent->right);
        !            90:        upparent->right = lower;
        !            91:     }
        !            92: 
        !            93:     lower->left = upper;
        !            94:     upper->parent = lower;
        !            95: }
        !            96: 
        !            97: /*
        !            98:  * This operation is the ``mirror'' image of rotate_left. It is
        !            99:  * the same procedure, but with left and right interchanged.
        !           100:  */
        !           101: 
        !           102: static void rotate_right(dnode_t *upper)
        !           103: {
        !           104:     dnode_t *lower, *lowright, *upparent;
        !           105: 
        !           106:     lower = upper->left;
        !           107:     upper->left = lowright = lower->right;
        !           108:     lowright->parent = upper;
        !           109: 
        !           110:     lower->parent = upparent = upper->parent;
        !           111: 
        !           112:     if (upper == upparent->right) {
        !           113:        upparent->right = lower;
        !           114:     } else {
        !           115:        assert (upper == upparent->left);
        !           116:        upparent->left = lower;
        !           117:     }
        !           118: 
        !           119:     lower->right = upper;
        !           120:     upper->parent = lower;
        !           121: }
        !           122: 
        !           123: /*
        !           124:  * Do a postorder traversal of the tree rooted at the specified
        !           125:  * node and free everything under it.  Used by dict_free().
        !           126:  */
        !           127: 
        !           128: static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil)
        !           129: {
        !           130:     if (node == nil)
        !           131:        return;
        !           132:     free_nodes(dict, node->left, nil);
        !           133:     free_nodes(dict, node->right, nil);
        !           134:     dict->freenode(node, dict->context);
        !           135: }
        !           136: 
        !           137: /*
        !           138:  * This procedure performs a verification that the given subtree is a binary
        !           139:  * search tree. It performs an inorder traversal of the tree using the
        !           140:  * dict_next() successor function, verifying that the key of each node is
        !           141:  * strictly lower than that of its successor, if duplicates are not allowed,
        !           142:  * or lower or equal if duplicates are allowed.  This function is used for
        !           143:  * debugging purposes. 
        !           144:  */
        !           145: 
        !           146: static int verify_bintree(dict_t *dict)
        !           147: {
        !           148:     dnode_t *first, *next;
        !           149: 
        !           150:     first = dict_first(dict);
        !           151: 
        !           152:     if (dict->dupes) {
        !           153:        while (first && (next = dict_next(dict, first))) {
        !           154:            if (dict->compare(first->key, next->key) > 0)
        !           155:                return 0;
        !           156:            first = next;
        !           157:        }
        !           158:     } else {
        !           159:        while (first && (next = dict_next(dict, first))) {
        !           160:            if (dict->compare(first->key, next->key) >= 0)
        !           161:                return 0;
        !           162:            first = next;
        !           163:        }
        !           164:     }
        !           165:     return 1;
        !           166: }
        !           167: 
        !           168: 
        !           169: /*
        !           170:  * This function recursively verifies that the given binary subtree satisfies
        !           171:  * three of the red black properties. It checks that every red node has only
        !           172:  * black children. It makes sure that each node is either red or black. And it
        !           173:  * checks that every path has the same count of black nodes from root to leaf.
        !           174:  * It returns the blackheight of the given subtree; this allows blackheights to
        !           175:  * be computed recursively and compared for left and right siblings for
        !           176:  * mismatches. It does not check for every nil node being black, because there
        !           177:  * is only one sentinel nil node. The return value of this function is the
        !           178:  * black height of the subtree rooted at the node ``root'', or zero if the
        !           179:  * subtree is not red-black.
        !           180:  */
        !           181: 
        !           182: static unsigned int verify_redblack(dnode_t *nil, dnode_t *root)
        !           183: {
        !           184:     unsigned height_left, height_right;
        !           185: 
        !           186:     if (root != nil) {
        !           187:        height_left = verify_redblack(nil, root->left);
        !           188:        height_right = verify_redblack(nil, root->right);
        !           189:        if (height_left == 0 || height_right == 0)
        !           190:            return 0;
        !           191:        if (height_left != height_right)
        !           192:            return 0;
        !           193:        if (root->color == dnode_red) {
        !           194:            if (root->left->color != dnode_black)
        !           195:                return 0;
        !           196:            if (root->right->color != dnode_black)
        !           197:                return 0;
        !           198:            return height_left;
        !           199:        }
        !           200:        if (root->color != dnode_black)
        !           201:            return 0;
        !           202:        return height_left + 1;
        !           203:     } 
        !           204:     return 1;
        !           205: }
        !           206: 
        !           207: /*
        !           208:  * Compute the actual count of nodes by traversing the tree and
        !           209:  * return it. This could be compared against the stored count to
        !           210:  * detect a mismatch.
        !           211:  */
        !           212: 
        !           213: static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root)
        !           214: {
        !           215:     if (root == nil)
        !           216:        return 0;
        !           217:     else
        !           218:        return 1 + verify_node_count(nil, root->left)
        !           219:            + verify_node_count(nil, root->right);
        !           220: }
        !           221: 
        !           222: /*
        !           223:  * Verify that the tree contains the given node. This is done by
        !           224:  * traversing all of the nodes and comparing their pointers to the
        !           225:  * given pointer. Returns 1 if the node is found, otherwise
        !           226:  * returns zero. It is intended for debugging purposes.
        !           227:  */
        !           228: 
        !           229: static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)
        !           230: {
        !           231:     if (root != nil) {
        !           232:        return root == node
        !           233:                || verify_dict_has_node(nil, root->left, node)
        !           234:                || verify_dict_has_node(nil, root->right, node);
        !           235:     }
        !           236:     return 0;
        !           237: }
        !           238: 
        !           239: 
        !           240: /*
        !           241:  * Dynamically allocate and initialize a dictionary object.
        !           242:  */
        !           243: 
        !           244: dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp)
        !           245: {
        !           246:     dict_t *new = malloc(sizeof *new);
        !           247: 
        !           248:     if (new) {
        !           249:        new->compare = comp;
        !           250:        new->allocnode = dnode_alloc;
        !           251:        new->freenode = dnode_free;
        !           252:        new->context = NULL;
        !           253:        new->nodecount = 0;
        !           254:        new->maxcount = maxcount;
        !           255:        new->nilnode.left = &new->nilnode;
        !           256:        new->nilnode.right = &new->nilnode;
        !           257:        new->nilnode.parent = &new->nilnode;
        !           258:        new->nilnode.color = dnode_black;
        !           259:        new->dupes = 0;
        !           260:     }
        !           261:     return new;
        !           262: }
        !           263: 
        !           264: /*
        !           265:  * Select a different set of node allocator routines.
        !           266:  */
        !           267: 
        !           268: void dict_set_allocator(dict_t *dict, dnode_alloc_t al,
        !           269:        dnode_free_t fr, void *context)
        !           270: {
        !           271:     assert (dict_count(dict) == 0);
        !           272:     assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL));
        !           273: 
        !           274:     dict->allocnode = al ? al : dnode_alloc;
        !           275:     dict->freenode = fr ? fr : dnode_free;
        !           276:     dict->context = context;
        !           277: }
        !           278: 
        !           279: /*
        !           280:  * Free a dynamically allocated dictionary object. Removing the nodes
        !           281:  * from the tree before deleting it is required.
        !           282:  */
        !           283: 
        !           284: void dict_destroy(dict_t *dict)
        !           285: {
        !           286:     assert (dict_isempty(dict));
        !           287:     free(dict);
        !           288: }
        !           289: 
        !           290: /*
        !           291:  * Free all the nodes in the dictionary by using the dictionary's
        !           292:  * installed free routine. The dictionary is emptied.
        !           293:  */
        !           294: 
        !           295: void dict_free_nodes(dict_t *dict)
        !           296: {
        !           297:     dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
        !           298:     free_nodes(dict, root, nil);
        !           299:     dict->nodecount = 0;
        !           300:     dict->nilnode.left = &dict->nilnode;
        !           301:     dict->nilnode.right = &dict->nilnode;
        !           302: }
        !           303: 
        !           304: /*
        !           305:  * Obsolescent function, equivalent to dict_free_nodes
        !           306:  */
        !           307: 
        !           308: void dict_free(dict_t *dict)
        !           309: {
        !           310: #ifdef KAZLIB_OBSOLESCENT_DEBUG
        !           311:     assert ("call to obsolescent function dict_free()" && 0);
        !           312: #endif
        !           313:     dict_free_nodes(dict);
        !           314: }
        !           315: 
        !           316: /*
        !           317:  * Initialize a user-supplied dictionary object.
        !           318:  */
        !           319: 
        !           320: dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp)
        !           321: {
        !           322:     dict->compare = comp;
        !           323:     dict->allocnode = dnode_alloc;
        !           324:     dict->freenode = dnode_free;
        !           325:     dict->context = NULL;
        !           326:     dict->nodecount = 0;
        !           327:     dict->maxcount = maxcount;
        !           328:     dict->nilnode.left = &dict->nilnode;
        !           329:     dict->nilnode.right = &dict->nilnode;
        !           330:     dict->nilnode.parent = &dict->nilnode;
        !           331:     dict->nilnode.color = dnode_black;
        !           332:     dict->dupes = 0;
        !           333:     return dict;
        !           334: }
        !           335: 
        !           336: /* 
        !           337:  * Initialize a dictionary in the likeness of another dictionary
        !           338:  */
        !           339: 
        !           340: void dict_init_like(dict_t *dict, const dict_t *template)
        !           341: {
        !           342:     dict->compare = template->compare;
        !           343:     dict->allocnode = template->allocnode;
        !           344:     dict->freenode = template->freenode;
        !           345:     dict->context = template->context;
        !           346:     dict->nodecount = 0;
        !           347:     dict->maxcount = template->maxcount;
        !           348:     dict->nilnode.left = &dict->nilnode;
        !           349:     dict->nilnode.right = &dict->nilnode;
        !           350:     dict->nilnode.parent = &dict->nilnode;
        !           351:     dict->nilnode.color = dnode_black;
        !           352:     dict->dupes = template->dupes;
        !           353: 
        !           354:     assert (dict_similar(dict, template));
        !           355: }
        !           356: 
        !           357: /*
        !           358:  * Remove all nodes from the dictionary (without freeing them in any way).
        !           359:  */
        !           360: 
        !           361: static void dict_clear(dict_t *dict)
        !           362: {
        !           363:     dict->nodecount = 0;
        !           364:     dict->nilnode.left = &dict->nilnode;
        !           365:     dict->nilnode.right = &dict->nilnode;
        !           366:     dict->nilnode.parent = &dict->nilnode;
        !           367:     assert (dict->nilnode.color == dnode_black);
        !           368: }
        !           369: 
        !           370: 
        !           371: /*
        !           372:  * Verify the integrity of the dictionary structure.  This is provided for
        !           373:  * debugging purposes, and should be placed in assert statements.   Just because
        !           374:  * this function succeeds doesn't mean that the tree is not corrupt. Certain
        !           375:  * corruptions in the tree may simply cause undefined behavior.
        !           376:  */ 
        !           377: 
        !           378: int dict_verify(dict_t *dict)
        !           379: {
        !           380:     dnode_t *nil = dict_nil(dict), *root = dict_root(dict);
        !           381: 
        !           382:     /* check that the sentinel node and root node are black */
        !           383:     if (root->color != dnode_black)
        !           384:        return 0;
        !           385:     if (nil->color != dnode_black)
        !           386:        return 0;
        !           387:     if (nil->right != nil)
        !           388:        return 0;
        !           389:     /* nil->left is the root node; check that its parent pointer is nil */
        !           390:     if (nil->left->parent != nil)
        !           391:        return 0;
        !           392:     /* perform a weak test that the tree is a binary search tree */
        !           393:     if (!verify_bintree(dict))
        !           394:        return 0;
        !           395:     /* verify that the tree is a red-black tree */
        !           396:     if (!verify_redblack(nil, root))
        !           397:        return 0;
        !           398:     if (verify_node_count(nil, root) != dict_count(dict))
        !           399:        return 0;
        !           400:     return 1;
        !           401: }
        !           402: 
        !           403: /*
        !           404:  * Determine whether two dictionaries are similar: have the same comparison and
        !           405:  * allocator functions, and same status as to whether duplicates are allowed.
        !           406:  */
        !           407: 
        !           408: int dict_similar(const dict_t *left, const dict_t *right)
        !           409: {
        !           410:     if (left->compare != right->compare)
        !           411:        return 0;
        !           412: 
        !           413:     if (left->allocnode != right->allocnode)
        !           414:        return 0;
        !           415: 
        !           416:     if (left->freenode != right->freenode)
        !           417:        return 0;
        !           418: 
        !           419:     if (left->context != right->context)
        !           420:        return 0;
        !           421: 
        !           422:     if (left->dupes != right->dupes)
        !           423:        return 0;
        !           424: 
        !           425:     return 1;
        !           426: }
        !           427: 
        !           428: /*
        !           429:  * Locate a node in the dictionary having the given key.
        !           430:  * If the node is not found, a null a pointer is returned (rather than 
        !           431:  * a pointer that dictionary's nil sentinel node), otherwise a pointer to the
        !           432:  * located node is returned.
        !           433:  */
        !           434: 
        !           435: dnode_t *dict_lookup(dict_t *dict, const void *key)
        !           436: {
        !           437:     dnode_t *root = dict_root(dict);
        !           438:     dnode_t *nil = dict_nil(dict);
        !           439:     dnode_t *saved;
        !           440:     int result;
        !           441: 
        !           442:     /* simple binary search adapted for trees that contain duplicate keys */
        !           443: 
        !           444:     while (root != nil) {
        !           445:        result = dict->compare(key, root->key);
        !           446:        if (result < 0)
        !           447:            root = root->left;
        !           448:        else if (result > 0)
        !           449:            root = root->right;
        !           450:        else {
        !           451:            if (!dict->dupes) { /* no duplicates, return match          */
        !           452:                return root;
        !           453:            } else {            /* could be dupes, find leftmost one    */
        !           454:                do {
        !           455:                    saved = root;
        !           456:                    root = root->left;
        !           457:                    while (root != nil && dict->compare(key, root->key))
        !           458:                        root = root->right;
        !           459:                } while (root != nil);
        !           460:                return saved;
        !           461:            }
        !           462:        }
        !           463:     }
        !           464: 
        !           465:     return NULL;
        !           466: }
        !           467: 
        !           468: /*
        !           469:  * Look for the node corresponding to the lowest key that is equal to or
        !           470:  * greater than the given key.  If there is no such node, return null.
        !           471:  */
        !           472: 
        !           473: dnode_t *dict_lower_bound(dict_t *dict, const void *key)
        !           474: {
        !           475:     dnode_t *root = dict_root(dict);
        !           476:     dnode_t *nil = dict_nil(dict);
        !           477:     dnode_t *tentative = 0;
        !           478: 
        !           479:     while (root != nil) {
        !           480:        int result = dict->compare(key, root->key);
        !           481: 
        !           482:        if (result > 0) {
        !           483:            root = root->right;
        !           484:        } else if (result < 0) {
        !           485:            tentative = root;
        !           486:            root = root->left;
        !           487:        } else {
        !           488:            if (!dict->dupes) {
        !           489:                return root;
        !           490:            } else {
        !           491:                tentative = root;
        !           492:                root = root->left;
        !           493:            }
        !           494:        } 
        !           495:     }
        !           496:     
        !           497:     return tentative;
        !           498: }
        !           499: 
        !           500: /*
        !           501:  * Look for the node corresponding to the greatest key that is equal to or
        !           502:  * lower than the given key.  If there is no such node, return null.
        !           503:  */
        !           504: 
        !           505: dnode_t *dict_upper_bound(dict_t *dict, const void *key)
        !           506: {
        !           507:     dnode_t *root = dict_root(dict);
        !           508:     dnode_t *nil = dict_nil(dict);
        !           509:     dnode_t *tentative = 0;
        !           510: 
        !           511:     while (root != nil) {
        !           512:        int result = dict->compare(key, root->key);
        !           513: 
        !           514:        if (result < 0) {
        !           515:            root = root->left;
        !           516:        } else if (result > 0) {
        !           517:            tentative = root;
        !           518:            root = root->right;
        !           519:        } else {
        !           520:            if (!dict->dupes) {
        !           521:                return root;
        !           522:            } else {
        !           523:                tentative = root;
        !           524:                root = root->right;
        !           525:            }
        !           526:        } 
        !           527:     }
        !           528:     
        !           529:     return tentative;
        !           530: }
        !           531: 
        !           532: /*
        !           533:  * Insert a node into the dictionary. The node should have been
        !           534:  * initialized with a data field. All other fields are ignored.
        !           535:  * The behavior is undefined if the user attempts to insert into
        !           536:  * a dictionary that is already full (for which the dict_isfull()
        !           537:  * function returns true).
        !           538:  */
        !           539: 
        !           540: void dict_insert(dict_t *dict, dnode_t *node, const void *key)
        !           541: {
        !           542:     dnode_t *where = dict_root(dict), *nil = dict_nil(dict);
        !           543:     dnode_t *parent = nil, *uncle, *grandpa;
        !           544:     int result = -1;
        !           545: 
        !           546:     node->key = key;
        !           547: 
        !           548:     assert (!dict_isfull(dict));
        !           549:     assert (!dict_contains(dict, node));
        !           550:     assert (!dnode_is_in_a_dict(node));
        !           551: 
        !           552:     /* basic binary tree insert */
        !           553: 
        !           554:     while (where != nil) {
        !           555:        parent = where;
        !           556:        result = dict->compare(key, where->key);
        !           557:        /* trap attempts at duplicate key insertion unless it's explicitly allowed */
        !           558:        assert (dict->dupes || result != 0);
        !           559:        if (result < 0)
        !           560:            where = where->left;
        !           561:        else
        !           562:            where = where->right;
        !           563:     }
        !           564: 
        !           565:     assert (where == nil);
        !           566: 
        !           567:     if (result < 0)
        !           568:        parent->left = node;
        !           569:     else
        !           570:        parent->right = node;
        !           571: 
        !           572:     node->parent = parent;
        !           573:     node->left = nil;
        !           574:     node->right = nil;
        !           575: 
        !           576:     dict->nodecount++;
        !           577: 
        !           578:     /* red black adjustments */
        !           579: 
        !           580:     node->color = dnode_red;
        !           581: 
        !           582:     while (parent->color == dnode_red) {
        !           583:        grandpa = parent->parent;
        !           584:        if (parent == grandpa->left) {
        !           585:            uncle = grandpa->right;
        !           586:            if (uncle->color == dnode_red) {    /* red parent, red uncle */
        !           587:                parent->color = dnode_black;
        !           588:                uncle->color = dnode_black;
        !           589:                grandpa->color = dnode_red;
        !           590:                node = grandpa;
        !           591:                parent = grandpa->parent;
        !           592:            } else {                            /* red parent, black uncle */
        !           593:                if (node == parent->right) {
        !           594:                    rotate_left(parent);
        !           595:                    parent = node;
        !           596:                    assert (grandpa == parent->parent);
        !           597:                    /* rotation between parent and child preserves grandpa */
        !           598:                }
        !           599:                parent->color = dnode_black;
        !           600:                grandpa->color = dnode_red;
        !           601:                rotate_right(grandpa);
        !           602:                break;
        !           603:            }
        !           604:        } else {        /* symmetric cases: parent == parent->parent->right */
        !           605:            uncle = grandpa->left;
        !           606:            if (uncle->color == dnode_red) {
        !           607:                parent->color = dnode_black;
        !           608:                uncle->color = dnode_black;
        !           609:                grandpa->color = dnode_red;
        !           610:                node = grandpa;
        !           611:                parent = grandpa->parent;
        !           612:            } else {
        !           613:                if (node == parent->left) {
        !           614:                    rotate_right(parent);
        !           615:                    parent = node;
        !           616:                    assert (grandpa == parent->parent);
        !           617:                }
        !           618:                parent->color = dnode_black;
        !           619:                grandpa->color = dnode_red;
        !           620:                rotate_left(grandpa);
        !           621:                break;
        !           622:            }
        !           623:        }
        !           624:     }
        !           625: 
        !           626:     dict_root(dict)->color = dnode_black;
        !           627: 
        !           628:     assert (dict_verify(dict));
        !           629: }
        !           630: 
        !           631: /*
        !           632:  * Delete the given node from the dictionary. If the given node does not belong
        !           633:  * to the given dictionary, undefined behavior results.  A pointer to the
        !           634:  * deleted node is returned.
        !           635:  */
        !           636: 
        !           637: dnode_t *dict_delete(dict_t *dict, dnode_t *delete)
        !           638: {
        !           639:     dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent;
        !           640: 
        !           641:     /* basic deletion */
        !           642: 
        !           643:     assert (!dict_isempty(dict));
        !           644:     assert (dict_contains(dict, delete));
        !           645: 
        !           646:     /*
        !           647:      * If the node being deleted has two children, then we replace it with its
        !           648:      * successor (i.e. the leftmost node in the right subtree.) By doing this,
        !           649:      * we avoid the traditional algorithm under which the successor's key and
        !           650:      * value *only* move to the deleted node and the successor is spliced out
        !           651:      * from the tree. We cannot use this approach because the user may hold
        !           652:      * pointers to the successor, or nodes may be inextricably tied to some
        !           653:      * other structures by way of embedding, etc. So we must splice out the
        !           654:      * node we are given, not some other node, and must not move contents from
        !           655:      * one node to another behind the user's back.
        !           656:      */
        !           657: 
        !           658:     if (delete->left != nil && delete->right != nil) {
        !           659:        dnode_t *next = dict_next(dict, delete);
        !           660:        dnode_t *nextparent = next->parent;
        !           661:        dnode_color_t nextcolor = next->color;
        !           662: 
        !           663:        assert (next != nil);
        !           664:        assert (next->parent != nil);
        !           665:        assert (next->left == nil);
        !           666: 
        !           667:        /*
        !           668:         * First, splice out the successor from the tree completely, by
        !           669:         * moving up its right child into its place.
        !           670:         */
        !           671: 
        !           672:        child = next->right;
        !           673:        child->parent = nextparent;
        !           674: 
        !           675:        if (nextparent->left == next) {
        !           676:            nextparent->left = child;
        !           677:        } else {
        !           678:            assert (nextparent->right == next);
        !           679:            nextparent->right = child;
        !           680:        }
        !           681: 
        !           682:        /*
        !           683:         * Now that the successor has been extricated from the tree, install it
        !           684:         * in place of the node that we want deleted.
        !           685:         */
        !           686: 
        !           687:        next->parent = delparent;
        !           688:        next->left = delete->left;
        !           689:        next->right = delete->right;
        !           690:        next->left->parent = next;
        !           691:        next->right->parent = next;
        !           692:        next->color = delete->color;
        !           693:        delete->color = nextcolor;
        !           694: 
        !           695:        if (delparent->left == delete) {
        !           696:            delparent->left = next;
        !           697:        } else {
        !           698:            assert (delparent->right == delete);
        !           699:            delparent->right = next;
        !           700:        }
        !           701: 
        !           702:     } else {
        !           703:        assert (delete != nil);
        !           704:        assert (delete->left == nil || delete->right == nil);
        !           705: 
        !           706:        child = (delete->left != nil) ? delete->left : delete->right;
        !           707: 
        !           708:        child->parent = delparent = delete->parent;         
        !           709: 
        !           710:        if (delete == delparent->left) {
        !           711:            delparent->left = child;    
        !           712:        } else {
        !           713:            assert (delete == delparent->right);
        !           714:            delparent->right = child;
        !           715:        }
        !           716:     }
        !           717: 
        !           718:     delete->parent = NULL;
        !           719:     delete->right = NULL;
        !           720:     delete->left = NULL;
        !           721: 
        !           722:     dict->nodecount--;
        !           723: 
        !           724:     assert (verify_bintree(dict));
        !           725: 
        !           726:     /* red-black adjustments */
        !           727: 
        !           728:     if (delete->color == dnode_black) {
        !           729:        dnode_t *parent, *sister;
        !           730: 
        !           731:        dict_root(dict)->color = dnode_red;
        !           732: 
        !           733:        while (child->color == dnode_black) {
        !           734:            parent = child->parent;
        !           735:            if (child == parent->left) {
        !           736:                sister = parent->right;
        !           737:                assert (sister != nil);
        !           738:                if (sister->color == dnode_red) {
        !           739:                    sister->color = dnode_black;
        !           740:                    parent->color = dnode_red;
        !           741:                    rotate_left(parent);
        !           742:                    sister = parent->right;
        !           743:                    assert (sister != nil);
        !           744:                }
        !           745:                if (sister->left->color == dnode_black
        !           746:                        && sister->right->color == dnode_black) {
        !           747:                    sister->color = dnode_red;
        !           748:                    child = parent;
        !           749:                } else {
        !           750:                    if (sister->right->color == dnode_black) {
        !           751:                        assert (sister->left->color == dnode_red);
        !           752:                        sister->left->color = dnode_black;
        !           753:                        sister->color = dnode_red;
        !           754:                        rotate_right(sister);
        !           755:                        sister = parent->right;
        !           756:                        assert (sister != nil);
        !           757:                    }
        !           758:                    sister->color = parent->color;
        !           759:                    sister->right->color = dnode_black;
        !           760:                    parent->color = dnode_black;
        !           761:                    rotate_left(parent);
        !           762:                    break;
        !           763:                }
        !           764:            } else {    /* symmetric case: child == child->parent->right */
        !           765:                assert (child == parent->right);
        !           766:                sister = parent->left;
        !           767:                assert (sister != nil);
        !           768:                if (sister->color == dnode_red) {
        !           769:                    sister->color = dnode_black;
        !           770:                    parent->color = dnode_red;
        !           771:                    rotate_right(parent);
        !           772:                    sister = parent->left;
        !           773:                    assert (sister != nil);
        !           774:                }
        !           775:                if (sister->right->color == dnode_black
        !           776:                        && sister->left->color == dnode_black) {
        !           777:                    sister->color = dnode_red;
        !           778:                    child = parent;
        !           779:                } else {
        !           780:                    if (sister->left->color == dnode_black) {
        !           781:                        assert (sister->right->color == dnode_red);
        !           782:                        sister->right->color = dnode_black;
        !           783:                        sister->color = dnode_red;
        !           784:                        rotate_left(sister);
        !           785:                        sister = parent->left;
        !           786:                        assert (sister != nil);
        !           787:                    }
        !           788:                    sister->color = parent->color;
        !           789:                    sister->left->color = dnode_black;
        !           790:                    parent->color = dnode_black;
        !           791:                    rotate_right(parent);
        !           792:                    break;
        !           793:                }
        !           794:            }
        !           795:        }
        !           796: 
        !           797:        child->color = dnode_black;
        !           798:        dict_root(dict)->color = dnode_black;
        !           799:     }
        !           800: 
        !           801:     assert (dict_verify(dict));
        !           802: 
        !           803:     return delete;
        !           804: }
        !           805: 
        !           806: /*
        !           807:  * Allocate a node using the dictionary's allocator routine, give it
        !           808:  * the data item.
        !           809:  */
        !           810: 
        !           811: int dict_alloc_insert(dict_t *dict, const void *key, void *data)
        !           812: {
        !           813:     dnode_t *node = dict->allocnode(dict->context);
        !           814: 
        !           815:     if (node) {
        !           816:        dnode_init(node, data);
        !           817:        dict_insert(dict, node, key);
        !           818:        return 1;
        !           819:     }
        !           820:     return 0;
        !           821: }
        !           822: 
        !           823: void dict_delete_free(dict_t *dict, dnode_t *node)
        !           824: {
        !           825:     dict_delete(dict, node);
        !           826:     dict->freenode(node, dict->context);
        !           827: }
        !           828: 
        !           829: /*
        !           830:  * Return the node with the lowest (leftmost) key. If the dictionary is empty
        !           831:  * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
        !           832:  */
        !           833: 
        !           834: dnode_t *dict_first(dict_t *dict)
        !           835: {
        !           836:     dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left;
        !           837: 
        !           838:     if (root != nil)
        !           839:        while ((left = root->left) != nil)
        !           840:            root = left;
        !           841: 
        !           842:     return (root == nil) ? NULL : root;
        !           843: }
        !           844: 
        !           845: /*
        !           846:  * Return the node with the highest (rightmost) key. If the dictionary is empty
        !           847:  * (that is, dict_isempty(dict) returns 1) a null pointer is returned.
        !           848:  */
        !           849: 
        !           850: dnode_t *dict_last(dict_t *dict)
        !           851: {
        !           852:     dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right;
        !           853: 
        !           854:     if (root != nil)
        !           855:        while ((right = root->right) != nil)
        !           856:            root = right;
        !           857: 
        !           858:     return (root == nil) ? NULL : root;
        !           859: }
        !           860: 
        !           861: /*
        !           862:  * Return the given node's successor node---the node which has the
        !           863:  * next key in the the left to right ordering. If the node has
        !           864:  * no successor, a null pointer is returned rather than a pointer to
        !           865:  * the nil node.
        !           866:  */
        !           867: 
        !           868: dnode_t *dict_next(dict_t *dict, dnode_t *curr)
        !           869: {
        !           870:     dnode_t *nil = dict_nil(dict), *parent, *left;
        !           871: 
        !           872:     if (curr->right != nil) {
        !           873:        curr = curr->right;
        !           874:        while ((left = curr->left) != nil)
        !           875:            curr = left;
        !           876:        return curr;
        !           877:     }
        !           878: 
        !           879:     parent = curr->parent;
        !           880: 
        !           881:     while (parent != nil && curr == parent->right) {
        !           882:        curr = parent;
        !           883:        parent = curr->parent;
        !           884:     }
        !           885: 
        !           886:     return (parent == nil) ? NULL : parent;
        !           887: }
        !           888: 
        !           889: /*
        !           890:  * Return the given node's predecessor, in the key order.
        !           891:  * The nil sentinel node is returned if there is no predecessor.
        !           892:  */
        !           893: 
        !           894: dnode_t *dict_prev(dict_t *dict, dnode_t *curr)
        !           895: {
        !           896:     dnode_t *nil = dict_nil(dict), *parent, *right;
        !           897: 
        !           898:     if (curr->left != nil) {
        !           899:        curr = curr->left;
        !           900:        while ((right = curr->right) != nil)
        !           901:            curr = right;
        !           902:        return curr;
        !           903:     }
        !           904: 
        !           905:     parent = curr->parent;
        !           906: 
        !           907:     while (parent != nil && curr == parent->left) {
        !           908:        curr = parent;
        !           909:        parent = curr->parent;
        !           910:     }
        !           911: 
        !           912:     return (parent == nil) ? NULL : parent;
        !           913: }
        !           914: 
        !           915: void dict_allow_dupes(dict_t *dict)
        !           916: {
        !           917:     dict->dupes = 1;
        !           918: }
        !           919: 
        !           920: #undef dict_count
        !           921: #undef dict_isempty
        !           922: #undef dict_isfull
        !           923: #undef dnode_get
        !           924: #undef dnode_put
        !           925: #undef dnode_getkey
        !           926: 
        !           927: dictcount_t dict_count(dict_t *dict)
        !           928: {
        !           929:     return dict->nodecount;
        !           930: }
        !           931: 
        !           932: int dict_isempty(dict_t *dict)
        !           933: {
        !           934:     return dict->nodecount == 0;
        !           935: }
        !           936: 
        !           937: int dict_isfull(dict_t *dict)
        !           938: {
        !           939:     return dict->nodecount == dict->maxcount;
        !           940: }
        !           941: 
        !           942: int dict_contains(dict_t *dict, dnode_t *node)
        !           943: {
        !           944:     return verify_dict_has_node(dict_nil(dict), dict_root(dict), node);
        !           945: }
        !           946: 
        !           947: static dnode_t *dnode_alloc(void *context)
        !           948: {
        !           949:     return malloc(sizeof *dnode_alloc(NULL));
        !           950: }
        !           951: 
        !           952: static void dnode_free(dnode_t *node, void *context)
        !           953: {
        !           954:     free(node);
        !           955: }
        !           956: 
        !           957: dnode_t *dnode_create(void *data)
        !           958: {
        !           959:     dnode_t *new = malloc(sizeof *new);
        !           960:     if (new) {
        !           961:        new->data = data;
        !           962:        new->parent = NULL;
        !           963:        new->left = NULL;
        !           964:        new->right = NULL;
        !           965:     }
        !           966:     return new;
        !           967: }
        !           968: 
        !           969: dnode_t *dnode_init(dnode_t *dnode, void *data)
        !           970: {
        !           971:     dnode->data = data;
        !           972:     dnode->parent = NULL;
        !           973:     dnode->left = NULL;
        !           974:     dnode->right = NULL;
        !           975:     return dnode;
        !           976: }
        !           977: 
        !           978: void dnode_destroy(dnode_t *dnode)
        !           979: {
        !           980:     assert (!dnode_is_in_a_dict(dnode));
        !           981:     free(dnode);
        !           982: }
        !           983: 
        !           984: void *dnode_get(dnode_t *dnode)
        !           985: {
        !           986:     return dnode->data;
        !           987: }
        !           988: 
        !           989: const void *dnode_getkey(dnode_t *dnode)
        !           990: {
        !           991:     return dnode->key;
        !           992: }
        !           993: 
        !           994: void dnode_put(dnode_t *dnode, void *data)
        !           995: {
        !           996:     dnode->data = data;
        !           997: }
        !           998: 
        !           999: int dnode_is_in_a_dict(dnode_t *dnode)
        !          1000: {
        !          1001:     return (dnode->parent && dnode->left && dnode->right);
        !          1002: }
        !          1003: 
        !          1004: void dict_process(dict_t *dict, void *context, dnode_process_t function)
        !          1005: {
        !          1006:     dnode_t *node = dict_first(dict), *next;
        !          1007: 
        !          1008:     while (node != NULL) {
        !          1009:        /* check for callback function deleting */
        !          1010:        /* the next node from under us          */
        !          1011:        assert (dict_contains(dict, node));
        !          1012:        next = dict_next(dict, node);
        !          1013:        function(dict, node, context);
        !          1014:        node = next;
        !          1015:     }
        !          1016: }
        !          1017: 
        !          1018: static void load_begin_internal(dict_load_t *load, dict_t *dict)
        !          1019: {
        !          1020:     load->dictptr = dict;
        !          1021:     load->nilnode.left = &load->nilnode;
        !          1022:     load->nilnode.right = &load->nilnode;
        !          1023: }
        !          1024: 
        !          1025: void dict_load_begin(dict_load_t *load, dict_t *dict)
        !          1026: {
        !          1027:     assert (dict_isempty(dict));
        !          1028:     load_begin_internal(load, dict);
        !          1029: }
        !          1030: 
        !          1031: void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key)
        !          1032: {
        !          1033:     dict_t *dict = load->dictptr;
        !          1034:     dnode_t *nil = &load->nilnode;
        !          1035:    
        !          1036:     assert (!dnode_is_in_a_dict(newnode));
        !          1037:     assert (dict->nodecount < dict->maxcount);
        !          1038: 
        !          1039:     #ifndef NDEBUG
        !          1040:     if (dict->nodecount > 0) {
        !          1041:        if (dict->dupes)
        !          1042:            assert (dict->compare(nil->left->key, key) <= 0);
        !          1043:        else
        !          1044:            assert (dict->compare(nil->left->key, key) < 0);
        !          1045:     }
        !          1046:     #endif
        !          1047: 
        !          1048:     newnode->key = key;
        !          1049:     nil->right->left = newnode;
        !          1050:     nil->right = newnode;
        !          1051:     newnode->left = nil;
        !          1052:     dict->nodecount++;
        !          1053: }
        !          1054: 
        !          1055: void dict_load_end(dict_load_t *load)
        !          1056: {
        !          1057:     dict_t *dict = load->dictptr;
        !          1058:     dnode_t *tree[DICT_DEPTH_MAX] = { 0 };
        !          1059:     dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next;
        !          1060:     dnode_t *complete = 0;
        !          1061:     dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount;
        !          1062:     dictcount_t botrowcount;
        !          1063:     unsigned baselevel = 0, level = 0, i;
        !          1064: 
        !          1065:     assert (dnode_red == 0 && dnode_black == 1);
        !          1066: 
        !          1067:     while (fullcount >= nodecount && fullcount)
        !          1068:        fullcount >>= 1;
        !          1069: 
        !          1070:     botrowcount = nodecount - fullcount;
        !          1071: 
        !          1072:     for (curr = loadnil->left; curr != loadnil; curr = next) {
        !          1073:        next = curr->left;
        !          1074: 
        !          1075:        if (complete == NULL && botrowcount-- == 0) {
        !          1076:            assert (baselevel == 0);
        !          1077:            assert (level == 0);
        !          1078:            baselevel = level = 1;
        !          1079:            complete = tree[0];
        !          1080: 
        !          1081:            if (complete != 0) {
        !          1082:                tree[0] = 0;
        !          1083:                complete->right = dictnil;
        !          1084:                while (tree[level] != 0) {
        !          1085:                    tree[level]->right = complete;
        !          1086:                    complete->parent = tree[level];
        !          1087:                    complete = tree[level];
        !          1088:                    tree[level++] = 0;
        !          1089:                }
        !          1090:            }
        !          1091:        }
        !          1092: 
        !          1093:        if (complete == NULL) {
        !          1094:            curr->left = dictnil;
        !          1095:            curr->right = dictnil;
        !          1096:            curr->color = level % 2;
        !          1097:            complete = curr;
        !          1098: 
        !          1099:            assert (level == baselevel);
        !          1100:            while (tree[level] != 0) {
        !          1101:                tree[level]->right = complete;
        !          1102:                complete->parent = tree[level];
        !          1103:                complete = tree[level];
        !          1104:                tree[level++] = 0;
        !          1105:            }
        !          1106:        } else {
        !          1107:            curr->left = complete;
        !          1108:            curr->color = (level + 1) % 2;
        !          1109:            complete->parent = curr;
        !          1110:            tree[level] = curr;
        !          1111:            complete = 0;
        !          1112:            level = baselevel;
        !          1113:        }
        !          1114:     }
        !          1115: 
        !          1116:     if (complete == NULL)
        !          1117:        complete = dictnil;
        !          1118: 
        !          1119:     for (i = 0; i < DICT_DEPTH_MAX; i++) {
        !          1120:        if (tree[i] != 0) {
        !          1121:            tree[i]->right = complete;
        !          1122:            complete->parent = tree[i];
        !          1123:            complete = tree[i];
        !          1124:        }
        !          1125:     }
        !          1126: 
        !          1127:     dictnil->color = dnode_black;
        !          1128:     dictnil->right = dictnil;
        !          1129:     complete->parent = dictnil;
        !          1130:     complete->color = dnode_black;
        !          1131:     dict_root(dict) = complete;
        !          1132: 
        !          1133:     assert (dict_verify(dict));
        !          1134: }
        !          1135: 
        !          1136: void dict_merge(dict_t *dest, dict_t *source)
        !          1137: {
        !          1138:     dict_load_t load;
        !          1139:     dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source);
        !          1140: 
        !          1141:     assert (dict_similar(dest, source));       
        !          1142: 
        !          1143:     if (source == dest)
        !          1144:        return;
        !          1145: 
        !          1146:     dest->nodecount = 0;
        !          1147:     load_begin_internal(&load, dest);
        !          1148: 
        !          1149:     for (;;) {
        !          1150:        if (leftnode != NULL && rightnode != NULL) {
        !          1151:            if (dest->compare(leftnode->key, rightnode->key) < 0)
        !          1152:                goto copyleft;
        !          1153:            else
        !          1154:                goto copyright;
        !          1155:        } else if (leftnode != NULL) {
        !          1156:            goto copyleft;
        !          1157:        } else if (rightnode != NULL) {
        !          1158:            goto copyright;
        !          1159:        } else {
        !          1160:            assert (leftnode == NULL && rightnode == NULL);
        !          1161:            break;
        !          1162:        }
        !          1163: 
        !          1164:     copyleft:
        !          1165:        {
        !          1166:            dnode_t *next = dict_next(dest, leftnode);
        !          1167:            #ifndef NDEBUG
        !          1168:            leftnode->left = NULL;      /* suppress assertion in dict_load_next */
        !          1169:            #endif
        !          1170:            dict_load_next(&load, leftnode, leftnode->key);
        !          1171:            leftnode = next;
        !          1172:            continue;
        !          1173:        }
        !          1174:        
        !          1175:     copyright:
        !          1176:        {
        !          1177:            dnode_t *next = dict_next(source, rightnode);
        !          1178:            #ifndef NDEBUG
        !          1179:            rightnode->left = NULL;
        !          1180:            #endif
        !          1181:            dict_load_next(&load, rightnode, rightnode->key);
        !          1182:            rightnode = next;
        !          1183:            continue;
        !          1184:        }
        !          1185:     }
        !          1186: 
        !          1187:     dict_clear(source);
        !          1188:     dict_load_end(&load);
        !          1189: }
        !          1190: 
        !          1191: #ifdef KAZLIB_TEST_MAIN
        !          1192: 
        !          1193: #include <stdio.h>
        !          1194: #include <string.h>
        !          1195: #include <ctype.h>
        !          1196: #include <stdarg.h>
        !          1197: 
        !          1198: typedef char input_t[256];
        !          1199: 
        !          1200: static int tokenize(char *string, ...)
        !          1201: {
        !          1202:     char **tokptr; 
        !          1203:     va_list arglist;
        !          1204:     int tokcount = 0;
        !          1205: 
        !          1206:     va_start(arglist, string);
        !          1207:     tokptr = va_arg(arglist, char **);
        !          1208:     while (tokptr) {
        !          1209:        while (*string && isspace((unsigned char) *string))
        !          1210:            string++;
        !          1211:        if (!*string)
        !          1212:            break;
        !          1213:        *tokptr = string;
        !          1214:        while (*string && !isspace((unsigned char) *string))
        !          1215:            string++;
        !          1216:        tokptr = va_arg(arglist, char **);
        !          1217:        tokcount++;
        !          1218:        if (!*string)
        !          1219:            break;
        !          1220:        *string++ = 0;
        !          1221:     }
        !          1222:     va_end(arglist);
        !          1223: 
        !          1224:     return tokcount;
        !          1225: }
        !          1226: 
        !          1227: static int comparef(const void *key1, const void *key2)
        !          1228: {
        !          1229:     return strcmp(key1, key2);
        !          1230: }
        !          1231: 
        !          1232: static char *dupstring(char *str)
        !          1233: {
        !          1234:     int sz = strlen(str) + 1;
        !          1235:     char *new = malloc(sz);
        !          1236:     if (new)
        !          1237:        memcpy(new, str, sz);
        !          1238:     return new;
        !          1239: }
        !          1240: 
        !          1241: static dnode_t *new_node(void *c)
        !          1242: {
        !          1243:     static dnode_t few[5];
        !          1244:     static int count;
        !          1245: 
        !          1246:     if (count < 5)
        !          1247:        return few + count++;
        !          1248: 
        !          1249:     return NULL;
        !          1250: }
        !          1251: 
        !          1252: static void del_node(dnode_t *n, void *c)
        !          1253: {
        !          1254: }
        !          1255: 
        !          1256: static int prompt = 0;
        !          1257: 
        !          1258: static void construct(dict_t *d)
        !          1259: {
        !          1260:     input_t in;
        !          1261:     int done = 0;
        !          1262:     dict_load_t dl;
        !          1263:     dnode_t *dn;
        !          1264:     char *tok1, *tok2, *val;
        !          1265:     const char *key;
        !          1266:     char *help = 
        !          1267:        "p                      turn prompt on\n"
        !          1268:        "q                      finish construction\n"
        !          1269:        "a <key> <val>          add new entry\n";
        !          1270: 
        !          1271:     if (!dict_isempty(d))
        !          1272:        puts("warning: dictionary not empty!");
        !          1273: 
        !          1274:     dict_load_begin(&dl, d);
        !          1275: 
        !          1276:     while (!done) {
        !          1277:        if (prompt)
        !          1278:            putchar('>');
        !          1279:        fflush(stdout);
        !          1280: 
        !          1281:        if (!fgets(in, sizeof(input_t), stdin))
        !          1282:            break;
        !          1283: 
        !          1284:        switch (in[0]) {
        !          1285:            case '?':
        !          1286:                puts(help);
        !          1287:                break;
        !          1288:            case 'p':
        !          1289:                prompt = 1;
        !          1290:                break;
        !          1291:            case 'q':
        !          1292:                done = 1;
        !          1293:                break;
        !          1294:            case 'a':
        !          1295:                if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
        !          1296:                    puts("what?");
        !          1297:                    break;
        !          1298:                }
        !          1299:                key = dupstring(tok1);
        !          1300:                val = dupstring(tok2);
        !          1301:                dn = dnode_create(val);
        !          1302: 
        !          1303:                if (!key || !val || !dn) {
        !          1304:                    puts("out of memory");
        !          1305:                    free((void *) key);
        !          1306:                    free(val);
        !          1307:                    if (dn)
        !          1308:                        dnode_destroy(dn);
        !          1309:                }
        !          1310: 
        !          1311:                dict_load_next(&dl, dn, key);
        !          1312:                break;
        !          1313:            default:
        !          1314:                putchar('?');
        !          1315:                putchar('\n');
        !          1316:                break;
        !          1317:        }
        !          1318:     }
        !          1319: 
        !          1320:     dict_load_end(&dl);
        !          1321: }
        !          1322: 
        !          1323: int main(void)
        !          1324: {
        !          1325:     input_t in;
        !          1326:     dict_t darray[10];
        !          1327:     dict_t *d = &darray[0];
        !          1328:     dnode_t *dn;
        !          1329:     int i;
        !          1330:     char *tok1, *tok2, *val;
        !          1331:     const char *key;
        !          1332: 
        !          1333:     char *help =
        !          1334:        "a <key> <val>          add value to dictionary\n"
        !          1335:        "d <key>                delete value from dictionary\n"
        !          1336:        "l <key>                lookup value in dictionary\n"
        !          1337:        "( <key>                lookup lower bound\n"
        !          1338:        ") <key>                lookup upper bound\n"
        !          1339:        "# <num>                switch to alternate dictionary (0-9)\n"
        !          1340:        "j <num> <num>          merge two dictionaries\n"
        !          1341:        "f                      free the whole dictionary\n"
        !          1342:        "k                      allow duplicate keys\n"
        !          1343:        "c                      show number of entries\n"
        !          1344:        "t                      dump whole dictionary in sort order\n"
        !          1345:        "m                      make dictionary out of sorted items\n"
        !          1346:        "p                      turn prompt on\n"
        !          1347:        "s                      switch to non-functioning allocator\n"
        !          1348:        "q                      quit";
        !          1349: 
        !          1350:     for (i = 0; i < sizeof darray / sizeof *darray; i++)
        !          1351:        dict_init(&darray[i], DICTCOUNT_T_MAX, comparef);
        !          1352: 
        !          1353:     for (;;) {
        !          1354:        if (prompt)
        !          1355:            putchar('>');
        !          1356:        fflush(stdout);
        !          1357: 
        !          1358:        if (!fgets(in, sizeof(input_t), stdin))
        !          1359:            break;
        !          1360: 
        !          1361:        switch(in[0]) {
        !          1362:            case '?':
        !          1363:                puts(help);
        !          1364:                break;
        !          1365:            case 'a':
        !          1366:                if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
        !          1367:                    puts("what?");
        !          1368:                    break;
        !          1369:                }
        !          1370:                key = dupstring(tok1);
        !          1371:                val = dupstring(tok2);
        !          1372: 
        !          1373:                if (!key || !val) {
        !          1374:                    puts("out of memory");
        !          1375:                    free((void *) key);
        !          1376:                    free(val);
        !          1377:                }
        !          1378: 
        !          1379:                if (!dict_alloc_insert(d, key, val)) {
        !          1380:                    puts("dict_alloc_insert failed");
        !          1381:                    free((void *) key);
        !          1382:                    free(val);
        !          1383:                    break;
        !          1384:                }
        !          1385:                break;
        !          1386:            case 'd':
        !          1387:                if (tokenize(in+1, &tok1, (char **) 0) != 1) {
        !          1388:                    puts("what?");
        !          1389:                    break;
        !          1390:                }
        !          1391:                dn = dict_lookup(d, tok1);
        !          1392:                if (!dn) {
        !          1393:                    puts("dict_lookup failed");
        !          1394:                    break;
        !          1395:                }
        !          1396:                val = dnode_get(dn);
        !          1397:                key = dnode_getkey(dn);
        !          1398:                dict_delete_free(d, dn);
        !          1399: 
        !          1400:                free(val);
        !          1401:                free((void *) key);
        !          1402:                break;
        !          1403:            case 'f':
        !          1404:                dict_free(d);
        !          1405:                break;
        !          1406:            case 'l':
        !          1407:            case '(':
        !          1408:            case ')':
        !          1409:                if (tokenize(in+1, &tok1, (char **) 0) != 1) {
        !          1410:                    puts("what?");
        !          1411:                    break;
        !          1412:                }
        !          1413:                dn = 0;
        !          1414:                switch (in[0]) {
        !          1415:                case 'l':
        !          1416:                    dn = dict_lookup(d, tok1);
        !          1417:                    break;
        !          1418:                case '(':
        !          1419:                    dn = dict_lower_bound(d, tok1);
        !          1420:                    break;
        !          1421:                case ')':
        !          1422:                    dn = dict_upper_bound(d, tok1);
        !          1423:                    break;
        !          1424:                }
        !          1425:                if (!dn) {
        !          1426:                    puts("lookup failed");
        !          1427:                    break;
        !          1428:                }
        !          1429:                val = dnode_get(dn);
        !          1430:                puts(val);
        !          1431:                break;
        !          1432:            case 'm':
        !          1433:                construct(d);
        !          1434:                break;
        !          1435:            case 'k':
        !          1436:                dict_allow_dupes(d);
        !          1437:                break;
        !          1438:            case 'c':
        !          1439:                printf("%lu\n", (unsigned long) dict_count(d));
        !          1440:                break;
        !          1441:            case 't':
        !          1442:                for (dn = dict_first(d); dn; dn = dict_next(d, dn)) {
        !          1443:                    printf("%s\t%s\n", (char *) dnode_getkey(dn),
        !          1444:                            (char *) dnode_get(dn));
        !          1445:                }
        !          1446:                break;
        !          1447:            case 'q':
        !          1448:                exit(0);
        !          1449:                break;
        !          1450:            case '\0':
        !          1451:                break;
        !          1452:            case 'p':
        !          1453:                prompt = 1;
        !          1454:                break;
        !          1455:            case 's':
        !          1456:                dict_set_allocator(d, new_node, del_node, NULL);
        !          1457:                break;
        !          1458:            case '#':
        !          1459:                if (tokenize(in+1, &tok1, (char **) 0) != 1) {
        !          1460:                    puts("what?");
        !          1461:                    break;
        !          1462:                } else {
        !          1463:                    int dictnum = atoi(tok1);
        !          1464:                    if (dictnum < 0 || dictnum > 9) {
        !          1465:                        puts("invalid number");
        !          1466:                        break;
        !          1467:                    }
        !          1468:                    d = &darray[dictnum];
        !          1469:                }
        !          1470:                break;
        !          1471:            case 'j':
        !          1472:                if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) {
        !          1473:                    puts("what?");
        !          1474:                    break;
        !          1475:                } else {
        !          1476:                    int dict1 = atoi(tok1), dict2 = atoi(tok2);
        !          1477:                    if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) {
        !          1478:                        puts("invalid number");
        !          1479:                        break;
        !          1480:                    }
        !          1481:                    dict_merge(&darray[dict1], &darray[dict2]);
        !          1482:                }
        !          1483:                break;
        !          1484:            default:
        !          1485:                putchar('?');
        !          1486:                putchar('\n');
        !          1487:                break;
        !          1488:        }
        !          1489:     }
        !          1490: 
        !          1491:     return 0;
        !          1492: }
        !          1493: 
        !          1494: #endif

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