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