1 /***********************************************************************/
2 /* Open Visualization Data Explorer                                    */
3 /* (C) Copyright IBM Corp. 1989,1999                                   */
4 /* ALL RIGHTS RESERVED                                                 */
5 /* This code licensed under the                                        */
6 /*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
7 /***********************************************************************/
8 
9 #include <dxconfig.h>
10 
11 
12 #include <stdio.h>
13 #include <string.h>
14 
15 #include <dx/dx.h>
16 
17 #include "config.h"
18 #include "crc.h"
19 #include "d.h"
20 #include "graph.h"
21 #include "utils.h"
22 #include "sysvars.h"
23 #include "distp.h"
24 
25 #define	DICT_LOCK(l,d)		if (l) DXlock (&(d)->lock, exJID)
26 #define	DICT_UNLOCK(l,d)	if (l) DXunlock (&(d)->lock, exJID)
27 
28 typedef struct _EXDictElement 	   	   *EXDictElement;
29 typedef struct _EXDictElementSorted	   *EXDictElementSorted;
30 
31 typedef struct _EXDictElement
32 {
33     EXDictElement		next;	/* the element chain		*/
34     EXDictElement		prev;
35     char			*key;	/* symbolic key			*/
36     Pointer			hash;	/* hash of key			*/
37     EXObj			obj;	/* data with the key		*/
38 } _EXDictElement;
39 
40 typedef struct _EXDictElementSorted
41 {
42     struct _EXDictElement       de;
43     EXDictElementSorted		newer;	/* the sort chain		*/
44     EXDictElementSorted		older;
45 } _EXDictElementSorted;
46 
47 typedef struct _EXDictHead
48 {
49     EXDictElement		e;	/* element pointer		*/
50 } _EXDictHead, *EXDictHead;
51 
52 typedef struct	 _EXDictionary
53 {
54     int				items;	/* number of in table		*/
55     int				iterIndex;	/* current iterator index */
56     EXDictElement		iterItem;	/* current iterator item */
57     int				mask;	/* bit mask for size		*/
58     int				locking;/* is locking required		*/
59     int				size;	/* size of table		*/
60     int				local;	/* is this a local dictionary	*/
61     EXDictElement		free;	/* element free list		*/
62     lock_type			lock;	/* lock if necessary		*/
63     int				sorted; /* is a sort list kept?		*/
64     EXDictElementSorted		newest; /* sort list head 		*/
65     EXDictElementSorted		oldest;	/* sort list tail 		*/
66     int				reverse;
67     _EXDictHead			h[1];	/* the elements in the table	*/
68 } _EXDictionary;
69 
70 static void _dxf_ExRemoveFromSortList(EXDictionary d, EXDictElement de);
71 static void _dxf_ExMakeNewest(EXDictionary d, EXDictElement de);
72 
__ExDictionaryCreate(int size,int local,int locking,int sorted)73 static EXDictionary __ExDictionaryCreate (int size, int local,
74 						int locking, int sorted)
75 {
76     int			n;
77     EXDictionary	d;
78     Error		l;
79 
80 #ifdef DICT_TIMING
81 DXMarkTimeLocal("D create");
82 #endif
83     /*
84      * Adjust the inputs so that they match our notion of things.  Round
85      * up to a power of 2 so that the masking will work.  If a dictionary
86      * is in local memory then it doesn't need locking.
87      */
88 
89     size    = (size <= 0) ? 1 : _dxf_ExNextPowerOf2 (size);
90     locking = local ? FALSE : locking;
91 
92     /*
93      * OK, now let's construct the dictionary and fill in the blanks.
94      */
95 
96     n  = sizeof (_EXDictionary);
97     n += sizeof (_EXDictHead) * size;
98 
99     d = (EXDictionary) (local ? DXAllocateLocal (n) : DXAllocate (n));
100     if (! d)
101 	_dxf_ExDie ("_dxf_ExDictionaryCreate:  DXAllocate failed");
102 
103     ExZero (d, n);
104 
105     d->mask	= size - 1;
106     d->locking	= locking;
107     d->size	= size;
108     d->local	= local;
109 
110     d->sorted   = sorted;
111     d->newest   = NULL;
112     d->oldest   = NULL;
113 
114     if (locking)
115     {
116 	l = DXcreate_lock (&d->lock, "Dictionary");
117 	if (l != OK)
118 	    _dxf_ExDie ("_dxf_ExDictionaryCreate:  DXcreate_lock failed");
119     }
120 
121 #ifdef DICT_TIMING
122 DXMarkTimeLocal("-D create");
123 #endif
124     return (d);
125 }
126 
127 /*
128  * Constructs a new dictionary based upon the following characteristics:
129  *
130  * size		Number of buckets to create
131  * local	Whether dictionary should reside in local memory
132  * locking	Whether dictionary requires locking
133  */
_dxf_ExDictionaryCreate(int size,int local,int locking)134 EXDictionary _dxf_ExDictionaryCreate (int size, int local, int locking)
135 {
136     return __ExDictionaryCreate(size, local, locking, 0);
137 }
138 
_dxf_ExDictionaryCreateSorted(int size,int local,int locking)139 EXDictionary _dxf_ExDictionaryCreateSorted (int size, int local, int locking)
140 {
141     return __ExDictionaryCreate(size, local, locking, 1);
142 }
143 
144 
145 /*
146  * Destroys a dictionary.  We need not bother with locking here since we
147  * assume that a dictionary will only be destroyed when no-one else is
148  * going to use it.
149  */
150 
_dxf_ExDictionaryDestroy(EXDictionary d)151 Error _dxf_ExDictionaryDestroy (EXDictionary d)
152 {
153     int			i;
154     EXDictHead		h;
155     EXDictElement	e, ne;
156 
157 #ifdef DICT_TIMING
158 DXMarkTimeLocal("D destroy");
159 #endif
160     if (! d)
161 	return (OK);
162 
163     /*
164      * Get rid of the free element list.
165      */
166 
167     for (e = d->free; e; e = ne)
168     {
169 	ne = e->next;
170 	DXFree ((Pointer) e);
171     }
172 
173     /*
174      * Destroy all of the records in the table.
175      */
176 
177     for (i = d->size, h = d->h; i--; h++)
178     {
179 	for (e = h->e; e; e = ne)
180 	{
181 	    ne = e->next;
182 	    ExDelete (e->obj);			/* delete its value	*/
183 	    DXFree ((Pointer) e->key);		/* destroy the key	*/
184 	    DXFree ((Pointer) e);			/* get rid of the block	*/
185 	}
186     }
187 
188     if (d->locking)
189 	DXdestroy_lock (&d->lock);
190 
191     DXFree ((Pointer) d);
192 
193 #ifdef DICT_TIMING
194 DXMarkTimeLocal("-D destroy");
195 #endif
196     return (OK);
197 }
198 
199 /* Releases all unneeded memory, returned TRUE if any memory is freed */
_dxf_ExDictionaryCompact(EXDictionary d)200 int _dxf_ExDictionaryCompact (EXDictionary d)
201 {
202     EXDictElement	e, ne;
203     int			result;
204 
205 #ifdef DICT_TIMING
206 DXMarkTimeLocal("D compact");
207 #endif
208     if (! d)
209 	return (FALSE);
210 
211     DICT_LOCK (d->locking, d);
212 
213     result = d->free != NULL;
214     /*
215      * Get rid of the free element list.
216      */
217     for (e = d->free; e; e = ne)
218     {
219 	ne = e->next;
220 	DXFree ((Pointer) e);
221     }
222     d->free = NULL;
223 
224     DICT_UNLOCK (d->locking, d);
225 
226 #ifdef DICT_TIMING
227 DXMarkTimeLocal("-D compact");
228 #endif
229     return (result);
230 }
231 
232 /*
233  * Empties a dictionary.  Returns true if any memory has been freed.
234  */
235 
_dxf_ExDictionaryPurge(EXDictionary d)236 int _dxf_ExDictionaryPurge (EXDictionary d)
237 {
238     int			i;
239     EXDictHead		h;
240     EXDictElement	e, ne;
241     int			result;
242 
243 #ifdef DICT_TIMING
244 DXMarkTimeLocal("D purge");
245 #endif
246     if (! d)
247 	return (FALSE);
248 
249     if(!_dxd_exRemoteSlave)
250         _dxf_ExDistributeMsg(DM_FLUSHDICT, (Pointer)d, 0, TOSLAVES);
251 
252     DICT_LOCK (d->locking, d);
253 
254     /*
255      * Destroy all of the records in the table.
256      */
257     for (result = FALSE, i = d->size, h = d->h; i--; h++)
258     {
259 	for (e = h->e, h->e = NULL; e; e = ne)
260 	{
261 	    ne = e->next;
262 
263 	    /* add node to free list	*/
264 	    e->next = d->free;
265 	    d->free = e;
266 
267 	    if (d->sorted)
268 		_dxf_ExRemoveFromSortList(d, e);
269 
270 	    ExDelete (e->obj);
271 	    DXFree ((Pointer) e->key);
272 
273 	    result = TRUE;
274 	}
275     }
276 
277     DICT_UNLOCK (d->locking, d);
278 
279 #ifdef DICT_TIMING
280 DXMarkTimeLocal("-D purge");
281 #endif
282     return (result);
283 }
284 
285 
286 /*
287  * Searches for the dictionary element associated with the given key.
288  * If it is found then it is returned, otherwise NULL is returned.
289  *
290  * NOTE:  If the dictionary requires locking then the locking should be
291  * performed outside of this routine.
292  */
293 
294 static EXDictElement
ExDictionarySearchE(EXDictionary d,int b,char * key,Pointer hash)295 ExDictionarySearchE (EXDictionary d, int b, char *key, Pointer hash)
296 {
297     EXDictElement	e;
298 
299     for (e = d->h[b].e; e; e = e->next)
300 	if ((hash == e->hash) && ! strcmp (key, e->key))
301 	{
302 	    if (d->sorted)
303 		_dxf_ExMakeNewest(d, e);
304 	    return (e);
305 	}
306 
307     return (NULL);
308 }
309 
310 
311 /*
312  * Searches the given dictionary for an object associated with the given key.
313  * If an entry is found then its value is returned, otherwise NULL is returned.
314  */
315 
_dxf_ExDictionarySearch(EXDictionary d,char * key)316 EXObj _dxf_ExDictionarySearch (EXDictionary d, char *key)
317 {
318     Pointer		h;			/* hash value		*/
319     int			b;			/* bucket id		*/
320     int			l;			/* locking?		*/
321     EXDictElement	e;			/* the found element	*/
322     EXObj		o;			/* the found object	*/
323 
324 #ifdef DICT_TIMING
325 DXMarkTimeLocal("D search");
326 #endif
327     if (d->items == 0)
328 	return (NULL);
329 
330     h = (Pointer) _dxf_ExCRCString (EX_INITIAL_CRC, key);
331     b = (long) h & d->mask;
332     l = d->locking;
333 
334     if (! d->h[b].e)				/* a quick out		*/
335 	return (NULL);
336 
337     DICT_LOCK (l, d);
338     e = ExDictionarySearchE (d, b, key, h);
339     if (e)
340     {
341 	o = e->obj;
342 	ExReference (o);
343     }
344     else
345 	o = NULL;
346 
347     DICT_UNLOCK (l, d);
348 
349 #ifdef DICT_TIMING
350 DXMarkTimeLocal("-D search");
351 #endif
352 
353     return (o);
354 }
355 
356 
357 static EXDictElement
_dxf_ExAllocateNewDictionaryElement(EXDictionary d)358 _dxf_ExAllocateNewDictionaryElement(EXDictionary d)
359 {
360     int size;
361 
362     if (d->sorted)
363 	size = sizeof(struct _EXDictElementSorted);
364     else
365 	size = sizeof(struct _EXDictElement);
366 
367     return d->local ?
368 	    (EXDictElement)DXAllocateLocalZero(size) :
369 	    (EXDictElement)DXAllocateZero(size);
370 }
371 
372 /*
373  * Inserts a new element into a dictionary.
374  */
375 
_dxf_ExDictionaryInsert(EXDictionary d,char * key,EXObj obj)376 Error _dxf_ExDictionaryInsert (EXDictionary d, char *key, EXObj obj)
377 {
378     Pointer		h;
379     int			b;
380     int			l;
381     Pointer		k;
382     EXDictElement	e, ne;
383     EXObj		o;
384 
385 #ifdef DICT_TIMING
386 DXMarkTimeLocal("D insert");
387 #endif
388 
389     ExReference (obj);
390 
391     h = (Pointer) _dxf_ExCRCString (EX_INITIAL_CRC, key);
392     b = (long) h & d->mask;
393     l = d->locking;
394 
395     DICT_LOCK (l, d);
396 
397     e = d->h[b].e ? ExDictionarySearchE (d, b, key, h) : NULL;
398 
399     /*
400      * If we find something with the given key then just replace the object.
401      * If not then we need to construct a new dictionary element, fill out
402      * its fields and link it into the structure.  Just to be sure, however,
403      * we redo the search to make sure that no-one snuck something with the
404      * same key in on us.
405      */
406     if (e)
407     {
408 	o      = e->obj;			/* remember for delete	*/
409 	e->obj = obj;				/* replace object	*/
410 	DICT_UNLOCK (l, d);
411 	ExDelete (o);
412 
413 	if (_dxf_ExIsDictionarySorted(d))
414 	    _dxf_ExMakeNewest(d, e);
415 
416     }
417     else
418     {
419 	/*
420 	 * Get an element block.  If we can find one from the free list the
421 	 * make use of it, otherwise go ahead and allocate one.  Once we
422 	 * have the block then go ahead and fill in its fields.
423 	 */
424 
425 	if (d->free)
426 	{
427 	    ne = d->free;
428 	    d->free = ne->next;
429 	    DICT_UNLOCK (l, d);
430 	}
431 	else
432 	{
433 	    DICT_UNLOCK (l, d);
434 
435 	    ne = _dxf_ExAllocateNewDictionaryElement(d);
436 	    if (! ne)
437 		_dxf_ExDie ("_dxf_ExDictionaryInsert:  can't DXAllocate");
438 	}
439 
440 	ne->prev = NULL;
441 	ne->key  = d->local ? _dxf_ExCopyStringLocal (key) : _dxf_ExCopyString (key);
442 	ne->obj  = obj;
443 	ne->hash = h;
444 
445 	/*
446 	 * Redo the search.
447 	 */
448 
449 	if (l)
450 	{
451 	    DICT_LOCK (l, d);
452 	    e = d->h[b].e ? ExDictionarySearchE (d, b, key, h) : NULL;
453 
454 	    /*
455 	     * If someone snuck one in on us then just replace the data and
456 	     * get rid of the one we created.
457 	     */
458 
459 	    if (e)
460 	    {
461 		o        = e->obj;		/* remember for delete	*/
462 		e->obj   = obj;			/* replace object	*/
463 		k        = ne->key;		/* remember for delete	*/
464 		ne->next = d->free;		/* free element block	*/
465 		d->free  = ne;
466 
467 		if (_dxf_ExIsDictionarySorted(d))
468 		    _dxf_ExMakeNewest(d, e);
469 
470 		DICT_UNLOCK (l, d);
471 
472 		ExDelete (o);			/* delete old object	*/
473 		DXFree ((Pointer) k);		/* delete new key	*/
474 	    }
475 	    else
476 	    {
477 		if (d->h[b].e)			/* fill in back pointer	*/
478 		    d->h[b].e->prev = ne;
479 		ne->next  = d->h[b].e;		/* link in new element	*/
480 		d->h[b].e = ne;
481 		d->items++;			/* bump item count	*/
482 
483 		if (_dxf_ExIsDictionarySorted(d))
484 		    _dxf_ExMakeNewest(d, ne);
485 
486 		DICT_UNLOCK (l, d);
487 	    }
488 	}
489 	else
490 	{
491 	    if (d->h[b].e)			/* fill in back pointer	*/
492 		d->h[b].e->prev = ne;
493 	    ne->next  = d->h[b].e;		/* link in new element	*/
494 	    d->h[b].e = ne;
495 	    d->items++;				/* bump item count	*/
496 	}
497     }
498 
499 #ifdef DICT_TIMING
500 DXMarkTimeLocal("-D insert");
501 #endif
502     return (OK);
503 }
504 
505 
506 /*
507  * Deletes an element from a dictionary
508  */
509 
_dxf_ExDictionaryDelete(EXDictionary d,Pointer key)510 Error _dxf_ExDictionaryDelete (EXDictionary d, Pointer key)
511 {
512     Pointer		h;
513     int			b;
514     int			l;
515     Pointer		k;
516     EXDictElement	e;
517     EXObj		o;
518 
519 #ifdef DICT_TIMING
520 DXMarkTimeLocal("D delete");
521 #endif
522 
523     if (d->items == 0)
524 	return (ERROR);
525 
526     h = (Pointer) _dxf_ExCRCString (EX_INITIAL_CRC, key);
527     b = (long) h & d->mask;
528     l = d->locking;
529 
530     DICT_LOCK (l, d);
531     e = ExDictionarySearchE (d, b, key, h);
532 
533     if (! e)					/* a quick out		*/
534     {
535 	DICT_UNLOCK (l, d);
536 	return (ERROR);
537     }
538 
539     o = e->obj;					/* remember for delete	*/
540     k = e->key;					/* remember for delete	*/
541 
542     if (e->next)				/* unlink 		*/
543 	e->next->prev = e->prev;
544 
545     if (e->prev)
546 	e->prev->next = e->next;
547     else
548 	d->h[b].e = e->next;
549 
550     e->next = d->free;				/* add to free list	*/
551     d->free = e;
552     d->items--;
553 
554     if (d->sorted)
555 	_dxf_ExRemoveFromSortList(d, e);
556 
557     DICT_UNLOCK (l, d);
558 
559     ExDelete (o);
560     DXFree ((Pointer) k);
561 
562 #ifdef DICT_TIMING
563 DXMarkTimeLocal("-D delete");
564 #endif
565 
566     return (OK);
567 }
568 
569 
570 /*
571  * Deletes an element from a dictionary.  This ignores locking because
572  * it is intended to be called while iterating through the dictionary
573  * using the ExDictionary*Iterate functions.
574  */
575 
_dxf_ExDictionaryDeleteNoLock(EXDictionary d,Pointer key)576 Error _dxf_ExDictionaryDeleteNoLock (EXDictionary d, Pointer key)
577 {
578     Pointer		h;
579     int			b;
580     Pointer		k;
581     EXDictElement	e;
582     EXObj		o;
583 
584 #ifdef DICT_TIMING
585 DXMarkTimeLocal("D del NL");
586 #endif
587 
588     if (d->items == 0)
589 	return (ERROR);
590 
591     h = (Pointer) _dxf_ExCRCString (EX_INITIAL_CRC, key);
592     b = (long) h & d->mask;
593 
594     e = ExDictionarySearchE (d, b, key, h);
595 
596     if (! e)					/* a quick out		*/
597     {
598 	return (ERROR);
599     }
600 
601     o = e->obj;					/* remember for delete	*/
602     k = e->key;					/* remember for delete	*/
603 
604     if (e->next)				/* unlink 		*/
605 	e->next->prev = e->prev;
606 
607     if (e->prev)
608 	e->prev->next = e->next;
609     else
610 	d->h[b].e = e->next;
611 
612     if (d->iterItem == e)
613 	d->iterItem = e->next;
614 
615     e->next = d->free;				/* add to free list	*/
616     d->free = e;
617     d->items--;
618 
619     if (d->sorted)
620 	_dxf_ExRemoveFromSortList(d, e);
621 
622     ExDelete (o);
623     DXFree ((Pointer) k);
624 
625 #ifdef DICT_TIMING
626 DXMarkTimeLocal("-D del NL");
627 #endif
628 
629     return (OK);
630 }
631 
632 /* A set of routines to iterate the dictionary */
_dxf_ExDictionaryBeginIterate(EXDictionary d)633 Error _dxf_ExDictionaryBeginIterate (EXDictionary d)
634 {
635     if (!d)
636 	return (OK);
637 
638     DICT_LOCK (d->locking, d);
639 
640     d->iterIndex = -1;
641     d->iterItem = NULL;
642 
643     return (OK);
644 }
645 
_dxf_ExDictionaryIterate(EXDictionary d,char ** key)646 EXObj _dxf_ExDictionaryIterate (EXDictionary d, char **key)
647 {
648     EXObj		result;
649     EXDictElement	e = d->iterItem;
650     int			i = d->iterIndex;
651 
652     while (e == NULL)
653     {
654 	++i;
655 	if (i == d->size)
656 	{
657 	    *key = NULL;
658 	    return NULL;
659 	}
660 	e = d->h[i].e;
661     }
662 
663     result = e->obj;
664     *key = e->key;
665 
666     d->iterItem = e->next;
667     d->iterIndex = i;
668 
669     return (result);
670 }
671 
672 
_dxf_ExDictionaryIterateMany(EXDictionary d,char ** key,EXObj * obj,int n)673 int _dxf_ExDictionaryIterateMany (EXDictionary d, char **key, EXObj *obj, int n)
674 {
675     EXDictElement	e = d->iterItem;
676     int			i = d->iterIndex;
677     int			cnt = 0;
678 
679     if (i >= d->size)
680 	return (0);
681 
682     for (cnt = 0; cnt < n; )
683     {
684 	while (e == NULL)
685 	{
686 	    ++i;
687 	    if (i == d->size)
688 	    {
689 		d->iterItem  = NULL;
690 		d->iterIndex = i;
691 		return (cnt);
692 	    }
693 	    e = d->h[i].e;
694 	}
695 
696 	*key++ = e->key;
697 	*obj++ = e->obj;
698 	cnt++;
699 	e = e->next;
700     }
701 
702     d->iterItem = e;
703     d->iterIndex = i;
704     return (cnt);
705 }
706 
_dxf_ExDictionaryEndIterate(EXDictionary d)707 Error _dxf_ExDictionaryEndIterate (EXDictionary d)
708 {
709     DICT_UNLOCK (d->locking, d);
710     return (OK);
711 }
712 
_dxf_ExDictPrint(EXDictionary d)713 Error _dxf_ExDictPrint (EXDictionary d)
714 {
715     int			l, i, colision;
716     EXDictElement	e;
717 
718 
719     if (!d)
720 	return (OK);
721     l = d->locking;
722 
723     DICT_LOCK (l, d);
724 
725     for (i = 0, e = d->free; e; ++i, e = e->next)
726 	;
727 
728     DXMessage ("Dictionary 0x%08x, size %d, %slocking, freelist size %d",
729                  d, d->size, l? "": "non-", i);
730     DXMessage("%25s | %4s | %2s | %10s",  "name", "bin", "cl", "object");
731     for (i = 0; i < d->size; ++i)
732     {
733 	for (colision = 0, e = d->h[i].e; e != NULL; e = e->next, ++colision)
734 	{
735             DXMessage ("%25s | %4d | %2d | 0x%08x", e->key, i, colision, e->obj);
736 	}
737     }
738 
739     DICT_UNLOCK (l, d);
740     return (OK);
741 }
742 
743 
744 void
_dxf_ExPrintSortList(EXDictionary d)745 _dxf_ExPrintSortList(EXDictionary d)
746 {
747     if (! d->sorted)
748 	DXMessage("dictionary is not sorted");
749     else
750     {
751 	EXDictElementSorted a = d->oldest, b = d->newest;
752 
753 
754 	DXMessage("o->n    n->o");
755 	while (a || b)
756 	{
757 	    DXMessage("0x%08lx 0x%08lx", a, b);
758 	    a = a->newer; b = b->older;
759 	}
760     }
761 }
762 
763 int
_dxf_ExIsDictionarySorted(EXDictionary d)764 _dxf_ExIsDictionarySorted(EXDictionary d)
765 {
766     return d->sorted;
767 }
768 
769 static void
_dxf_ExRemoveFromSortList(EXDictionary d,EXDictElement de)770 _dxf_ExRemoveFromSortList(EXDictionary d, EXDictElement de)
771 {
772     if (d->sorted)
773     {
774 	EXDictElementSorted sde = (EXDictElementSorted)de;
775 
776 	if (sde->older)
777 	    sde->older->newer = sde->newer;
778 	if (sde->newer)
779 	    sde->newer->older = sde->older;
780 
781 	if (d->newest == sde)
782 	    d->newest = sde->older;
783 
784 	if (d->oldest == sde)
785 	    d->oldest = sde->newer;
786 
787 	sde->newer = sde->older = NULL;
788     }
789 }
790 
791 static void
_dxf_ExMakeNewest(EXDictionary d,EXDictElement de)792 _dxf_ExMakeNewest(EXDictionary d, EXDictElement de)
793 {
794     if (d->sorted)
795     {
796 	EXDictElementSorted sde = (EXDictElementSorted)de;
797 
798 	if (d->newest == sde)
799 	    return;
800 
801 	if (sde->newer || sde->older)
802 	    _dxf_ExRemoveFromSortList(d, (EXDictElement)sde);
803 
804 	if (NULL != (sde->older = d->newest))
805 	    sde->older->newer = sde;
806 
807 	sde->newer = NULL;
808 
809 	d->newest  = sde;
810 
811 	if (d->oldest == NULL)
812 	    d->oldest = sde;
813     }
814 }
815 
816 
817 Error
_dxf_ExDictionaryBeginIterateSorted(EXDictionary d,int reverse)818 _dxf_ExDictionaryBeginIterateSorted(EXDictionary d, int reverse)
819 {
820     if (! d->sorted)
821     {
822 	DXSetError(ERROR_INTERNAL,
823 		"attempting to use _dxf_ExDictionaryBeginIterateSorted"
824 		"on an unsorted dictionary");
825 	return ERROR;
826     }
827 
828     if (reverse)
829     {
830 	d->reverse  = 1;
831 	d->iterItem = (EXDictElement)d->newest;
832     }
833     else
834     {
835 	d->reverse  = 0;
836 	d->iterItem = (EXDictElement)d->oldest;
837     }
838 
839     return OK;
840 }
841 
842 EXObj
_dxf_ExDictionaryIterateSorted(EXDictionary d,char ** key)843 _dxf_ExDictionaryIterateSorted(EXDictionary d, char **key)
844 {
845     EXDictElementSorted	e = (EXDictElementSorted)d->iterItem;
846 
847     if (! d->sorted)
848     {
849 	DXSetError(ERROR_INTERNAL,
850 		"attempting to use _dxf_ExDictionaryIterateSorted"
851 		"on an unsorted dictionary");
852 	return ERROR;
853     }
854 
855     if (e != NULL)
856     {
857 	if (d->reverse)
858 	    d->iterItem = (EXDictElement)(e->older);
859 	else
860 	    d->iterItem = (EXDictElement)(e->newer);
861 
862 	*key = e->de.key;
863 	return e->de.obj;
864     }
865     else
866     {
867 	*key = 0;
868 	return NULL;
869     }
870 }
871 
872 int
_dxf_ExDictionaryIterateSortedMany(EXDictionary d,char ** key,EXObj * obj,int n)873 _dxf_ExDictionaryIterateSortedMany (EXDictionary d, char **key, EXObj *obj, int n)
874 {
875     int nn;
876 
877     for (nn = 0; nn < n; nn++)
878 	if (NULL == (*obj++ = _dxf_ExDictionaryIterateSorted(d, key++)))
879 	    break;
880 
881     return nn;
882 }
883 
884