File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / isisd / dict.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:22:28 2012 UTC (11 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, v0_99_22p0, v0_99_22, v0_99_21, HEAD
quagga

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

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