Release 950403
[wine] / memory / local.c
1 /*
2  * Local heap functions
3  *
4  * Copyright 1995 Alexandre Julliard
5  */
6
7 /*
8  * Note:
9  * All local heap functions need the current DS as first parameter
10  * when called from the emulation library, so they take one more
11  * parameter than usual.
12  */
13
14 #include <stdlib.h>
15 #include <string.h>
16 #include "windows.h"
17 #include "ldt.h"
18 #include "instance.h"
19 #include "local.h"
20 #include "stackframe.h"
21 #include "toolhelp.h"
22 #include "stddebug.h"
23 #include "debug.h"
24
25
26 #ifndef WINELIB
27 #pragma pack(1)
28 #endif
29
30 typedef struct
31 {
32 /* Arena header */
33     WORD prev;          /* Previous arena | arena type */
34     WORD next;          /* Next arena */
35 /* Start of the memory block or free-list info */
36     WORD size;          /* Size of the free block */
37     WORD free_prev;     /* Previous free block */
38     WORD free_next;     /* Next free block */
39 } LOCALARENA;
40
41 #define ARENA_HEADER_SIZE      4
42
43   /* Arena types (stored in 'prev' field of the arena) */
44 #define LOCAL_ARENA_FREE       0
45 #define LOCAL_ARENA_FIXED      1
46 #define LOCAL_ARENA_MOVEABLE   3
47
48
49
50 typedef struct
51 {
52     WORD addr;                /* Address of the MOVEABLE block */
53     BYTE flags;               /* Flags for this block */
54     BYTE lock;                /* Lock count */
55 } LOCALHANDLEENTRY;
56
57 typedef struct
58 {
59     WORD check;               /* Heap checking flag */
60     WORD freeze;              /* Heap frozen flag */
61     WORD items;               /* Count of items on the heap */
62     WORD first;               /* First item of the heap */
63     WORD pad1;                /* Always 0 */
64     WORD last;                /* Last item of the heap */
65     WORD pad2;                /* Always 0 */
66     BYTE ncompact;            /* Compactions counter */
67     BYTE dislevel;            /* Discard level */
68     DWORD distotal;           /* Total bytes discarded */
69     WORD htable;              /* Pointer to handle table */
70     WORD hfree;               /* Pointer to free handle table */
71     WORD hdelta;              /* Delta to expand the handle table */
72     WORD expand;              /* Pointer to expand function (unused) */
73     WORD pstat;               /* Pointer to status structure (unused) */
74     DWORD notify WINE_PACKED; /* Pointer to LocalNotify() function */
75     WORD lock;                /* Lock count for the heap */
76     WORD extra;               /* Extra bytes to allocate when expanding */
77     WORD minsize;             /* Minimum size of the heap */
78     WORD magic;               /* Magic number */
79 } LOCALHEAPINFO;
80
81 #ifndef WINELIB
82 #pragma pack(4)
83 #endif
84
85 #define LOCAL_HEAP_MAGIC  0x484c  /* 'LH' */
86
87
88   /* All local heap allocations are aligned on 4-byte boundaries */
89 #define LALIGN(word)          (((word) + 3) & ~3)
90
91 #define ARENA_PTR(ptr,arena)       ((LOCALARENA *)((char*)(ptr)+(arena)))
92 #define ARENA_PREV(ptr,arena)      (ARENA_PTR(ptr,arena)->prev & ~3)
93 #define ARENA_NEXT(ptr,arena)      (ARENA_PTR(ptr,arena)->next)
94 #define ARENA_FLAGS(ptr,arena)     (ARENA_PTR(ptr,arena)->prev & 3)
95
96
97 /***********************************************************************
98  *           LOCAL_GetHeap
99  *
100  * Return a pointer to the local heap, making sure it exists.
101  */
102 static LOCALHEAPINFO *LOCAL_GetHeap( WORD ds )
103 {
104     LOCALHEAPINFO *pInfo;
105     INSTANCEDATA *ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( ds, 0 );
106     if (!ptr->heap) return 0;
107     pInfo = (LOCALHEAPINFO*)((char*)ptr + ptr->heap);
108     if (pInfo->magic != LOCAL_HEAP_MAGIC) return NULL;
109     return pInfo;
110 }
111
112
113 /***********************************************************************
114  *           LOCAL_AddFreeBlock
115  *
116  * Make a block free, inserting it in the free-list.
117  * 'block' is the handle of the block arena; 'baseptr' points to
118  * the beginning of the data segment containing the heap.
119  */
120 static void LOCAL_AddFreeBlock( char *baseptr, WORD block )
121 {
122     LOCALARENA *pArena, *pNext;
123     WORD next;
124
125       /* Mark the block as free */
126
127     pArena = ARENA_PTR( baseptr, block );
128     pArena->prev = (pArena->prev & ~3) | LOCAL_ARENA_FREE;
129     pArena->size = pArena->next - block;
130     
131       /* Find the next free block (last block is always free) */
132
133     next = pArena->next;
134     for (;;)
135     {
136         pNext = ARENA_PTR( baseptr, next );
137         if ((pNext->prev & 3) == LOCAL_ARENA_FREE) break;
138         next = pNext->next;
139     }
140
141       /* Insert the free block in the free-list */
142
143     pArena->free_prev = pNext->free_prev;
144     pArena->free_next = next;
145     ARENA_PTR(baseptr,pNext->free_prev)->free_next = block;
146     pNext->free_prev  = block;
147 }
148
149
150 /***********************************************************************
151  *           LOCAL_RemoveFreeBlock
152  *
153  * Remove a block from the free-list.
154  * 'block' is the handle of the block arena; 'baseptr' points to
155  * the beginning of the data segment containing the heap.
156  */
157 static void LOCAL_RemoveFreeBlock( char *baseptr, WORD block )
158 {
159       /* Mark the block as fixed */
160
161     LOCALARENA *pArena = ARENA_PTR( baseptr, block );
162     pArena->prev = (pArena->prev & ~3) | LOCAL_ARENA_FIXED;
163
164       /* Remove it from the list */
165
166     ARENA_PTR(baseptr,pArena->free_prev)->free_next = pArena->free_next;
167     ARENA_PTR(baseptr,pArena->free_next)->free_prev = pArena->free_prev;
168 }
169
170
171 /***********************************************************************
172  *           LOCAL_AddBlock
173  *
174  * Insert a new block in the heap.
175  * 'new' is the handle of the new block arena; 'baseptr' points to
176  * the beginning of the data segment containing the heap; 'prev' is
177  * the block before the new one.
178  */
179 static void LOCAL_AddBlock( char *baseptr, WORD prev, WORD new )
180 {
181     LOCALARENA *pPrev = ARENA_PTR( baseptr, prev );
182     LOCALARENA *pNew  = ARENA_PTR( baseptr, new );
183
184     pNew->prev = prev | LOCAL_ARENA_FIXED;
185     pNew->next = pPrev->next;
186     ARENA_PTR(baseptr,pPrev->next)->prev &= 3;
187     ARENA_PTR(baseptr,pPrev->next)->prev |= new;
188     pPrev->next = new;
189 }
190
191
192 /***********************************************************************
193  *           LOCAL_RemoveBlock
194  *
195  * Remove a block from the heap.
196  * 'block' is the handle of the block arena; 'baseptr' points to
197  * the beginning of the data segment containing the heap.
198  */
199 static void LOCAL_RemoveBlock( char *baseptr, WORD block )
200 {
201     LOCALARENA *pArena, *pTmp;
202
203       /* Remove the block from the free-list */
204
205     pArena = ARENA_PTR( baseptr, block );
206     if ((pArena->prev & 3) == LOCAL_ARENA_FREE)
207         LOCAL_RemoveFreeBlock( baseptr, block );
208
209       /* If the previous block is free, expand its size */
210
211     pTmp = ARENA_PTR( baseptr, pArena->prev & ~3 );
212     if ((pTmp->prev & 3) == LOCAL_ARENA_FREE)
213         pTmp->size += pArena->next - block;
214
215       /* Remove the block from the linked list */
216
217     pTmp->next = pArena->next;
218     pTmp = ARENA_PTR( baseptr, pArena->next );
219     pTmp->prev = (pTmp->prev & 3) | (pArena->prev & ~3);
220 }
221
222
223 /***********************************************************************
224  *           LOCAL_PrintHeap
225  */
226 static void LOCAL_PrintHeap( WORD ds )
227 {
228     char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
229     LOCALHEAPINFO *pInfo = LOCAL_GetHeap( ds );
230     WORD arena;
231
232     if (!pInfo)
233     {
234         printf( "Local Heap corrupted!  ds=%04x\n", ds );
235         return;
236     }
237     printf( "Local Heap  ds=%04x first=%04x last=%04x items=%d\n",
238             ds, pInfo->first, pInfo->last, pInfo->items );
239
240     arena = pInfo->first;
241     for (;;)
242     {
243         LOCALARENA *pArena = ARENA_PTR(ptr,arena);
244         printf( "  %04x: prev=%04x next=%04x type=%d\n", arena,
245                 pArena->prev & ~3, pArena->next, pArena->prev & 3 );
246         if ((pArena->prev & 3) == LOCAL_ARENA_FREE)
247         {
248             printf( "        size=%d free_prev=%04x free_next=%04x\n",
249                     pArena->size, pArena->free_prev, pArena->free_next );
250             if (pArena->next == arena) break;  /* last one */
251             if (ARENA_PTR(ptr,pArena->free_next)->free_prev != arena)
252             {
253                 printf( "*** arena->free_next->free_prev != arena\n" );
254                 break;
255             }
256         }
257         if (pArena->next == arena)
258         {
259             printf( "*** last block is not marked free\n" );
260             break;
261         }
262         if ((ARENA_PTR(ptr,pArena->next)->prev & ~3) != arena)
263         {
264             printf( "*** arena->next->prev != arena\n" );
265             break;
266         }
267         arena = pArena->next;
268     }
269 }
270
271
272 /***********************************************************************
273  *           LocalInit   (KERNEL.4)
274  */
275 HLOCAL LocalInit( WORD selector, WORD start, WORD end )
276 {
277     char *ptr;
278     WORD heapInfoArena, freeArena, lastArena;
279     LOCALHEAPINFO *pHeapInfo;
280     LOCALARENA *pArena, *pFirstArena, *pLastArena;
281
282       /* The initial layout of the heap is: */
283       /* - first arena         (FIXED)      */
284       /* - heap info structure (FIXED)      */
285       /* - large free block    (FREE)       */
286       /* - last arena          (FREE)       */
287
288     dprintf_local(stddeb, "LocalInit: %04x %04x-%04x\n", selector, start, end);
289     if (!selector) selector = CURRENT_DS;
290     ptr = PTR_SEG_OFF_TO_LIN( selector, 0 );
291     pHeapInfo = LOCAL_GetHeap(selector);
292       /* If there's already a local heap in this segment, */
293       /* we simply return TRUE. Helps some programs, but  */
294       /* does not seem to be 100% correct yet (there are  */
295       /* still some "heap corrupted" messages in LocalAlloc */
296     if (pHeapInfo)  {
297       dprintf_local(stddeb,"LocalInit: Heap %04x initialized twice.\n",selector);
298       if (debugging_local) LOCAL_PrintHeap(selector);
299       return TRUE;
300     }
301     start = LALIGN( max( start, sizeof(INSTANCEDATA) ) );
302     heapInfoArena = LALIGN(start + sizeof(LOCALARENA) );
303     freeArena = LALIGN( heapInfoArena + ARENA_HEADER_SIZE
304                         + sizeof(LOCALHEAPINFO) );
305     lastArena = (end - sizeof(LOCALARENA)) & ~3;
306
307       /* Make sure there's enough space.       */
308
309     if (freeArena + sizeof(LOCALARENA) >= lastArena) return FALSE;
310
311       /* Initialise the first arena */
312
313     pFirstArena = ARENA_PTR( ptr, start );
314     pFirstArena->prev      = start | LOCAL_ARENA_FIXED;
315     pFirstArena->next      = heapInfoArena;
316     pFirstArena->size      = LALIGN(sizeof(LOCALARENA));
317     pFirstArena->free_prev = start;  /* this one */
318     pFirstArena->free_next = freeArena;
319
320       /* Initialise the arena of the heap info structure */
321
322     pArena = ARENA_PTR( ptr, heapInfoArena );
323     pArena->prev = start | LOCAL_ARENA_FIXED;
324     pArena->next = freeArena;
325
326       /* Initialise the heap info structure */
327
328     pHeapInfo = (LOCALHEAPINFO *) (ptr + heapInfoArena + ARENA_HEADER_SIZE );
329     memset( pHeapInfo, 0, sizeof(LOCALHEAPINFO) );
330     pHeapInfo->items   = 4;
331     pHeapInfo->first   = start;
332     pHeapInfo->last    = lastArena;
333     pHeapInfo->hdelta  = 0x20;
334     pHeapInfo->extra   = 0x200;
335     pHeapInfo->minsize = lastArena - freeArena;
336     pHeapInfo->magic   = LOCAL_HEAP_MAGIC;
337
338       /* Initialise the large free block */
339
340     pArena = ARENA_PTR( ptr, freeArena );
341     pArena->prev      = heapInfoArena | LOCAL_ARENA_FREE;
342     pArena->next      = lastArena;
343     pArena->size      = lastArena - freeArena;
344     pArena->free_prev = start;
345     pArena->free_next = lastArena;
346
347       /* Initialise the last block */
348
349     pLastArena = ARENA_PTR( ptr, lastArena );
350     pLastArena->prev      = heapInfoArena | LOCAL_ARENA_FREE;
351     pLastArena->next      = lastArena;  /* this one */
352     pLastArena->size      = LALIGN(sizeof(LOCALARENA));
353     pLastArena->free_prev = freeArena;
354     pLastArena->free_next = lastArena;  /* this one */
355
356       /* Store the local heap address in the instance data */
357
358     ((INSTANCEDATA *)ptr)->heap = heapInfoArena + ARENA_HEADER_SIZE;
359     return TRUE;
360 }
361
362
363 /***********************************************************************
364  *           LOCAL_Alloc
365  *
366  * Implementation of LocalAlloc().
367  */
368 HLOCAL LOCAL_Alloc( WORD ds, WORD flags, WORD size )
369 {
370     char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
371     LOCALHEAPINFO *pInfo;
372     LOCALARENA *pArena;
373     WORD arena;
374
375     dprintf_local( stddeb, "LocalAlloc: %04x %d ds=%04x\n", flags, size, ds );
376
377       /* Find a suitable free block */
378
379     if (!(pInfo = LOCAL_GetHeap( ds ))) {
380           LOCAL_PrintHeap(ds);
381       return 0;
382     }
383     size += ARENA_HEADER_SIZE;
384     size = LALIGN( max( size, sizeof(LOCALARENA) ) );
385     arena = pInfo->first;
386     pArena = ARENA_PTR( ptr, arena );
387     for (;;)
388     {
389         if (arena == pArena->free_next) {
390           LOCAL_PrintHeap(ds);
391            return 0;  /* not found */
392         }
393         arena = pArena->free_next;
394         pArena = ARENA_PTR( ptr, arena );
395         if (pArena->size >= size) break;
396     }
397
398       /* Make a block out of the free arena */
399
400     if (pArena->size > size + LALIGN(sizeof(LOCALARENA)))
401     {
402         LOCAL_AddBlock( ptr, arena, arena+size );
403         LOCAL_AddFreeBlock( ptr, arena+size );
404         pInfo->items++;
405     }
406     LOCAL_RemoveFreeBlock( ptr, arena );
407
408     dprintf_local( stddeb, "LocalAlloc: returning %04x\n",
409                    arena + ARENA_HEADER_SIZE );
410     return arena + ARENA_HEADER_SIZE;
411 }
412
413
414 /***********************************************************************
415  *           LOCAL_ReAlloc
416  *
417  * Implementation of LocalReAlloc().
418  */
419 HLOCAL LOCAL_ReAlloc( WORD ds, HLOCAL handle, WORD size, WORD flags )
420 {
421     char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
422     LOCALHEAPINFO *pInfo;
423     LOCALARENA *pArena, *pNext;
424     WORD arena, newhandle;
425
426     dprintf_local( stddeb, "LocalReAlloc: %04x %d %04x ds=%04x\n",
427                    handle, size, flags, ds );
428     if (!(pInfo = LOCAL_GetHeap( ds ))) return 0;
429     arena = handle - ARENA_HEADER_SIZE;
430     pArena = ARENA_PTR( ptr, arena );
431     if (!size) size = 1;
432     size = LALIGN( size );
433
434       /* Check for size reduction */
435
436     if (size < pArena->next - handle)
437     {
438         if (handle + size < pArena->next - LALIGN(sizeof(LOCALARENA)))
439         {
440               /* It is worth making a new free block */
441             LOCAL_AddBlock( ptr, arena, handle + size );
442             LOCAL_AddFreeBlock( ptr, handle + size );
443             pInfo->items++;
444         }
445         dprintf_local( stddeb, "LocalReAlloc: returning %04x\n", handle );
446         return handle;
447     }
448
449       /* Check if the next block is free */
450
451     pNext = ARENA_PTR( ptr, pArena->next );
452     if (((pNext->prev & 3) == LOCAL_ARENA_FREE) &&
453         (size <= pNext->next - handle))
454     {
455         LOCAL_RemoveBlock( ptr, pArena->next );
456         if (handle + size < pArena->next - LALIGN(sizeof(LOCALARENA)))
457         {
458               /* It is worth making a new free block */
459             LOCAL_AddBlock( ptr, arena, handle + size );
460             LOCAL_AddFreeBlock( ptr, handle + size );
461             pInfo->items++;
462         }
463         dprintf_local( stddeb, "LocalReAlloc: returning %04x\n", handle );
464         return handle;
465     }
466
467       /* Now we have to allocate a new block */
468
469     newhandle = LOCAL_Alloc( ds, flags, size );
470     if (!newhandle) return 0;
471     memcpy( ptr + newhandle, ptr + handle, pArena->next - handle );
472     LOCAL_Free( ds, handle );
473     dprintf_local( stddeb, "LocalReAlloc: returning %04x\n", newhandle );
474     return newhandle;
475 }
476
477
478 /***********************************************************************
479  *           LOCAL_Free
480  *
481  * Implementation of LocalFree().
482  */
483 HLOCAL LOCAL_Free( WORD ds, HLOCAL handle )
484 {
485     char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
486     LOCALHEAPINFO *pInfo;
487     LOCALARENA *pArena, *pPrev, *pNext;
488     WORD arena;
489
490     dprintf_local( stddeb, "LocalFree: %04x ds=%04x\n", handle, ds );
491     if (!(pInfo = LOCAL_GetHeap( ds ))) return handle;
492     arena = handle - ARENA_HEADER_SIZE;
493     pArena = ARENA_PTR( ptr, arena );
494     if ((pArena->prev & 3) == LOCAL_ARENA_FREE) return handle;
495
496       /* Check if we can merge with the previous block */
497
498     pPrev = ARENA_PTR( ptr, pArena->prev & ~3 );
499     pNext = ARENA_PTR( ptr, pArena->next );
500     if ((pPrev->prev & 3) == LOCAL_ARENA_FREE)
501     {
502         arena  = pArena->prev & ~3;
503         pArena = pPrev;
504         LOCAL_RemoveBlock( ptr, pPrev->next );
505         pInfo->items--;
506     }
507     else  /* Make a new free block */
508     {
509         LOCAL_AddFreeBlock( ptr, arena );
510     }
511
512       /* Check if we can merge with the next block */
513
514     if ((pArena->next == pArena->free_next) &&
515         (pArena->next != pInfo->last))
516     {
517         LOCAL_RemoveBlock( ptr, pArena->next );
518         pInfo->items--;
519     }
520     return 0;
521 }
522
523
524 /***********************************************************************
525  *           LOCAL_Size
526  *
527  * Implementation of LocalSize().
528  */
529 WORD LOCAL_Size( WORD ds, HLOCAL handle )
530 {
531     LOCALARENA *pArena = PTR_SEG_OFF_TO_LIN( ds, handle - ARENA_HEADER_SIZE );
532     return pArena->next - handle;
533 }
534
535
536 /***********************************************************************
537  *           LOCAL_HeapSize
538  *
539  * Implementation of LocalHeapSize().
540  */
541 WORD LOCAL_HeapSize( WORD ds )
542 {
543     LOCALHEAPINFO *pInfo = LOCAL_GetHeap( ds );
544     if (!pInfo) return 0;
545     return pInfo->last - pInfo->first;
546 }
547
548
549 /***********************************************************************
550  *           LocalAlloc   (KERNEL.5)
551  */
552 HLOCAL LocalAlloc( WORD flags, WORD size )
553 {
554     return LOCAL_Alloc( CURRENT_DS, flags, size );
555 }
556
557
558 /***********************************************************************
559  *           LocalReAlloc   (KERNEL.6)
560  */
561 HLOCAL LocalReAlloc( HLOCAL handle, WORD flags, WORD size )
562 {
563     return LOCAL_ReAlloc( CURRENT_DS, handle, flags, size );
564 }
565
566
567 /***********************************************************************
568  *           LocalFree   (KERNEL.7)
569  */
570 HLOCAL LocalFree( HLOCAL handle )
571 {
572     return LOCAL_Free( CURRENT_DS, handle );
573 }
574
575
576 /***********************************************************************
577  *           LocalLock   (KERNEL.8)
578  */
579 WORD LocalLock( HLOCAL handle )
580 {
581     return handle;
582 }
583
584
585 /***********************************************************************
586  *           LocalUnlock   (KERNEL.9)
587  */
588 BOOL LocalUnlock( HLOCAL handle )
589 {
590     return TRUE;
591 }
592
593
594 /***********************************************************************
595  *           LocalSize   (KERNEL.10)
596  */
597 WORD LocalSize( HLOCAL handle )
598 {
599     return LOCAL_Size( CURRENT_DS, handle );
600 }
601
602
603 /***********************************************************************
604  *           LocalHandle   (KERNEL.11)
605  */
606 HLOCAL LocalHandle( WORD addr )
607 {
608     dprintf_local( stddeb, "LocalHandle: %04x\n", addr );
609     return addr;
610 }
611
612
613 /***********************************************************************
614  *           LocalFlags   (KERNEL.12)
615  */
616 WORD LocalFlags( HLOCAL handle )
617 {
618     dprintf_local( stddeb, "LocalFlags: %04x\n", handle );
619     return 0;
620 }
621
622
623 /***********************************************************************
624  *           LocalCompact   (KERNEL.13)
625  */
626 WORD LocalCompact( WORD minfree )
627 {
628 }
629
630
631 /***********************************************************************
632  *           LocalNotify   (KERNEL.14)
633  */
634 FARPROC LocalNotify( FARPROC func )
635 {
636 }
637
638
639 /***********************************************************************
640  *           LocalShrink   (KERNEL.121)
641  */
642 WORD LocalShrink( HLOCAL handle, WORD newsize )
643 {
644 }
645
646
647 /***********************************************************************
648  *           GetHeapSpaces   (KERNEL.138)
649  */
650 DWORD GetHeapSpaces( HMODULE module )
651 {
652     return MAKELONG( 0x7fff, 0xffff );
653 }
654
655
656 /***********************************************************************
657  *           LocalCountFree   (KERNEL.161)
658  */
659 void LocalCountFree()
660 {
661 }
662
663
664 /***********************************************************************
665  *           LocalHeapSize   (KERNEL.162)
666  */
667 WORD LocalHeapSize()
668 {
669     return LOCAL_HeapSize( CURRENT_DS );
670 }
671
672
673 /***********************************************************************
674  *           LocalHandleDelta   (KERNEL.310)
675  */
676 WORD LocalHandleDelta( WORD delta )
677 {
678 }
679
680
681 /***********************************************************************
682  *           LocalInfo   (TOOLHELP.56)
683  */
684 BOOL LocalInfo( LOCALINFO *pLocalInfo, HGLOBAL handle )
685 {
686     LOCALHEAPINFO *pInfo = LOCAL_GetHeap(SELECTOROF(WIN16_GlobalLock(handle)));
687     if (!pInfo) return FALSE;
688     pLocalInfo->wcItems = pInfo->items;
689     return TRUE;
690 }
691
692
693 /***********************************************************************
694  *           LocalFirst   (TOOLHELP.57)
695  */
696 BOOL LocalFirst( LOCALENTRY *pLocalEntry, HGLOBAL handle )
697 {
698     WORD ds = SELECTOROF( WIN16_GlobalLock( handle ) );
699     char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
700     LOCALHEAPINFO *pInfo = LOCAL_GetHeap( ds );
701     if (!pInfo) return FALSE;
702
703     pLocalEntry->hHandle   = pInfo->first + ARENA_HEADER_SIZE;
704     pLocalEntry->wAddress  = pLocalEntry->hHandle;
705     pLocalEntry->wFlags    = LF_FIXED;
706     pLocalEntry->wcLock    = 0;
707     pLocalEntry->wType     = LT_NORMAL;
708     pLocalEntry->hHeap     = handle;
709     pLocalEntry->wHeapType = NORMAL_HEAP;
710     pLocalEntry->wNext     = ARENA_PTR(ptr,pInfo->first)->next;
711     pLocalEntry->wSize     = pLocalEntry->wNext - pLocalEntry->hHandle;
712     return TRUE;
713 }
714
715
716 /***********************************************************************
717  *           LocalNext   (TOOLHELP.58)
718  */
719 BOOL LocalNext( LOCALENTRY *pLocalEntry )
720 {
721     WORD ds = SELECTOROF( pLocalEntry->hHeap );
722     char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
723     LOCALARENA *pArena;
724
725     if (!LOCAL_GetHeap( ds )) return FALSE;
726     if (!pLocalEntry->wNext) return FALSE;
727     pArena = ARENA_PTR( ptr, pLocalEntry->wNext );
728
729     pLocalEntry->hHandle   = pLocalEntry->wNext + ARENA_HEADER_SIZE;
730     pLocalEntry->wAddress  = pLocalEntry->hHandle;
731     pLocalEntry->wFlags    = (pArena->prev & 3) + 1;
732     pLocalEntry->wcLock    = 0;
733     pLocalEntry->wType     = LT_NORMAL;
734     if (pArena->next != pLocalEntry->wNext)  /* last one? */
735         pLocalEntry->wNext = pArena->next;
736     else
737         pLocalEntry->wNext = 0;
738     pLocalEntry->wSize     = pLocalEntry->wNext - pLocalEntry->hHandle;
739     return TRUE;
740 }