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