Release 950606
Tue Jun 6 12:11:41 1995 Alexandre Julliard (julliard@sunsite.unc.edu)
* [controls/menu.c]
Fixed bug with drawing multi-column menus with vertical separator.
* [debugger/debug.l]
Fixed NULL-pointer reference after readline().
* [if1632/winprocs.spec] [miscemu/int21.c] [miscemu/interrupts.c]
Added interrupt vector emulation. Allows to retrieve an interrupt
vector and jump to it without crashing.
* [loader/ldt.c]
Moved ldt.c to memory directory.
* [loader/task.c]
Implemented LockCurrentTask() and GetInstanceData().
* [objects/bitblt.c]
Fixed a bug that caused StretchBlt() to use wrong colors when
stretching a monochrome bitmap to a color display.
* [objects/bitmap.c]
Fixed a segmented pointer bug in CreateBitmapIndirect().
* [tools/build.c]
Added possibility to have arguments for register functions; used
by interrupt vectors to remove the flags from the stack.
Generate a new function CallTo32_LargeStack(), that allows calling
a 32-bit function using the original 32-bit stack, for functions
that need more that 64k of stack.
Tue May 30 10:29:56 1995 Martin von Loewis <martin@informatik.hu-berlin.de>
* [if1632/shell.spec] [misc/shell.c]
DoEnvironmentSubst: fixed prototype
* [if1632/gdi.spec] [objects/palette.c]
SetSystemPaletteUse: new function
* [if1632/kernel.spec] [loader/resource.c]
DirectResAlloc: new function
* [if1632/user.spec] [windows/keyboard.c]
SetKeyboardState: new function
Mon May 29 12:58:28 1995 Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>
* [tools/build.c]
Prevent interrupts from destroying the args for a 32 bit function
by loading the correct value into %esp directly after %ss.
* [loader/ne_image.c] [loader/module.c]
The new instance must be created earlier in LoadModule(), so that
fixups referencing it will be handled correctly.
Initialize the local heap for a DGROUP in NE_LoadSegment().
* [objects/dib.c]
Like RLE8 bitmaps, RLE4 bitmaps don't always end with a proper code.
This used to crash Wine. Fixed.
* [objects/text.c]
Fix possible null pointer dereference in debugging output.
* [misc/commdlg.c]
Handle user input in the edit control better. Some bugs fixed.
* [memory/local.c]
Started implementing moveable blocks. This is unfinished (!), but
at least it does not seem to break things.
Wed May 24 13:26:36 1995 Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>
* [loader/module.c]
LoadModule(): DLLs occasionally have a data segment, and they work
much better if it is loaded :-)
LoadLibrary(): pass HMODULE instead of HINSTANCE to NE_InitializeDLLs.
FindModule(): also strip off the last backslash of the pathnames
(Winhelp tried to load C:\WINDOWS\SYSTEM\COMMDLG.DLL).
GetModuleHandle(): just call MODULE_FindModule, it does the same job,
only better.
* [loader/ne_image.c]
LocalInit() the heap of a DLL in NE_InitDLL. (This is probably
not really correct, it seems that all programs and DLLs try to do
this themselves. But they pass weird parameters.)
NE_InitializeDLLs should also call NE_InitDLL for the passed hModule.
* [loader/task.c] [misc/user.c]
Finish global initializations in InitTask instead of InitApp, or
all the DLLs will be initialized in InitTask without any available
window classes!
diff --git a/memory/Imakefile b/memory/Imakefile
index 3364fec..8dbf16f 100644
--- a/memory/Imakefile
+++ b/memory/Imakefile
@@ -5,6 +5,7 @@
SRCS = \
selector.c \
global.c \
+ ldt.c \
local.c
OBJS = $(SRCS:.c=.o)
diff --git a/memory/global.c b/memory/global.c
index 7a0a144..d7fd15b 100644
--- a/memory/global.c
+++ b/memory/global.c
@@ -139,7 +139,7 @@
/* Fixup the size */
- if (size >= GLOBAL_MAX_ALLOC_SIZE - 0x0f) return 0;
+ if (size >= GLOBAL_MAX_ALLOC_SIZE - 0x1f) return 0;
if (size == 0) size = 0x20;
else size = (size + 0x1f) & ~0x1f;
diff --git a/memory/ldt.c b/memory/ldt.c
new file mode 100644
index 0000000..73e1260
--- /dev/null
+++ b/memory/ldt.c
@@ -0,0 +1,206 @@
+/*
+ * LDT manipulation functions
+ *
+ * Copyright 1993 Robert J. Amstadt
+ * Copyright 1995 Alexandre Julliard
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include "ldt.h"
+#include "stddebug.h"
+#include "debug.h"
+
+#ifndef WINELIB
+
+#ifdef linux
+#include <linux/unistd.h>
+#include <linux/head.h>
+#include <linux/ldt.h>
+
+_syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount)
+#endif /* linux */
+
+#if defined(__NetBSD__) || defined(__FreeBSD__)
+#include <machine/segments.h>
+
+extern int i386_get_ldt(int, union descriptor *, int);
+extern int i386_set_ldt(int, union descriptor *, int);
+#endif /* __NetBSD__ || __FreeBSD__ */
+
+#endif /* ifndef WINELIB */
+
+
+/***********************************************************************
+ * LDT_BytesToEntry
+ *
+ * Convert the raw bytes of the descriptor to an ldt_entry structure.
+ */
+static void LDT_BytesToEntry( unsigned long *buffer, ldt_entry *content )
+{
+ content->base = (*buffer >> 16) & 0x0000ffff;
+ content->limit = *buffer & 0x0000ffff;
+ buffer++;
+ content->base |= (*buffer & 0xff000000) | ((*buffer << 16) & 0x00ff0000);
+ content->limit |= (*buffer & 0x000f0000);
+ content->type = (*buffer >> 10) & 3;
+ content->seg_32bit = (*buffer & 0x00400000) != 0;
+ content->read_only = (*buffer & 0x00000200) == 0;
+ content->limit_in_pages = (*buffer & 0x00800000) != 0;
+}
+
+
+/***********************************************************************
+ * LDT_GetEntry
+ *
+ * Retrieve an LDT entry.
+ */
+int LDT_GetEntry( int entry, ldt_entry *content )
+{
+ int ret = 0;
+
+#ifdef WINELIB
+ content->base = ldt_copy[entry].base;
+ content->limit = ldt_copy[entry].limit;
+ content->type = SEGMENT_DATA;
+ content->seg_32bit = 0;
+ content->read_only = 0;
+ content->limit_in_pages = 0;
+#else /* WINELIB */
+
+#ifdef linux
+ int size = (entry + 1) * 2 * sizeof(long);
+ long *buffer = (long *) malloc( size );
+ ret = modify_ldt( 0, buffer, size );
+ LDT_BytesToEntry( &buffer[entry*2], content );
+ free( buffer );
+#endif /* linux */
+
+#if defined(__NetBSD__) || defined(__FreeBSD__)
+ long buffer[2];
+ ret = i386_get_ldt( entry, (union descriptor *)buffer, 1 );
+ LDT_BytesToEntry( buffer, content );
+#endif /* __NetBSD__ || __FreeBSD__ */
+
+#endif /* WINELIB */
+
+ return ret;
+}
+
+
+/***********************************************************************
+ * LDT_SetEntry
+ *
+ * Set an LDT entry.
+ */
+int LDT_SetEntry( int entry, ldt_entry *content )
+{
+ int ret = 0;
+
+ dprintf_ldt(stddeb,
+ "LDT_SetEntry: entry=%04x base=%08lx limit=%05lx %s %d-bit flags=%c%c%c\n",
+ entry, content->base, content->limit,
+ content->limit_in_pages ? "pages" : "bytes",
+ content->seg_32bit ? 32 : 16,
+ content->read_only && (content->type & SEGMENT_CODE) ? '-' : 'r',
+ content->read_only || (content->type & SEGMENT_CODE) ? '-' : 'w',
+ (content->type & SEGMENT_CODE) ? 'x' : '-' );
+
+#ifndef WINELIB
+#ifdef linux
+ {
+ struct modify_ldt_ldt_s ldt_info;
+
+ memset( &ldt_info, 0, sizeof(ldt_info) );
+ ldt_info.entry_number = entry;
+ ldt_info.base_addr = content->base;
+ ldt_info.limit = content->limit;
+ ldt_info.seg_32bit = content->seg_32bit != 0;
+ ldt_info.contents = content->type;
+ ldt_info.read_exec_only = content->read_only != 0;
+ ldt_info.limit_in_pages = content->limit_in_pages != 0;
+ ret = modify_ldt(1, &ldt_info, sizeof(ldt_info));
+ }
+#endif /* linux */
+
+#if defined(__NetBSD__) || defined(__FreeBSD__)
+ {
+ long d[2];
+
+ d[0] = ((content->base & 0x0000ffff) << 16) |
+ (content->limit & 0x0ffff);
+ d[1] = (content->base & 0xff000000) |
+ ((content->base & 0x00ff0000)>>16) |
+ (content->limit & 0xf0000) |
+ (content->type << 10) |
+ ((content->read_only == 0) << 9) |
+ ((content->seg_32bit != 0) << 22) |
+ ((content->limit_in_pages != 0) << 23) |
+ 0xf000;
+ ret = i386_set_ldt(entry, (union descriptor *)d, 1);
+ if (ret < 0)
+ {
+ perror("i386_set_ldt");
+ fprintf(stderr,
+ "Did you reconfigure the kernel with \"options USER_LDT\"?\n");
+ exit(1);
+ }
+ }
+#endif /* __NetBSD__ || __FreeBSD__ */
+#endif /* ifndef WINELIB */
+
+ if (ret < 0) return ret;
+ ldt_copy[entry].base = content->base;
+ if (!content->limit_in_pages) ldt_copy[entry].limit = content->limit;
+ else ldt_copy[entry].limit = (content->limit << 12) | 0x0fff;
+ return ret;
+}
+
+
+/***********************************************************************
+ * LDT_Print
+ *
+ * Print the content of the LDT on stdout.
+ */
+void LDT_Print()
+{
+ int i;
+
+#ifdef WINELIB
+ for (i = 0; i < LDT_SIZE; i++)
+ {
+ if (ldt_copy[i].base || ldt_copy[i].limit)
+ {
+ fprintf( stderr, "%04x: sel=%04x base=%08x limit=%05x\n",
+ i, ENTRY_TO_SELECTOR(i),
+ ldt_copy[i].base, ldt_copy[i].limit );
+ }
+ }
+#else /* WINELIB */
+
+ long buffer[2*LDT_SIZE];
+ ldt_entry content;
+ int n;
+
+#ifdef linux
+ n = modify_ldt( 0, buffer, sizeof(buffer) ) / 8;
+#endif /* linux */
+#if defined(__NetBSD__) || defined(__FreeBSD__)
+ n = i386_get_ldt( 0, (union descriptor *)buffer, LDT_SIZE );
+#endif /* __NetBSD__ || __FreeBSD__ */
+ for (i = 0; i < n; i++)
+ {
+ LDT_BytesToEntry( &buffer[2*i], &content );
+ if (content.base || content.limit)
+ {
+ fprintf( stderr, "%04x: sel=%04x base=%08lx limit=%05lx %s type=%d\n",
+ i, ENTRY_TO_SELECTOR(i),
+ content.base, content.limit,
+ content.limit_in_pages ? "(pages)" : "(bytes)",
+ content.type );
+ }
+ }
+#endif /* WINELIB */
+}
diff --git a/memory/local.c b/memory/local.c
index 134c1bf..1cd4a58 100644
--- a/memory/local.c
+++ b/memory/local.c
@@ -17,6 +17,7 @@
#include "ldt.h"
#include "instance.h"
#include "local.h"
+#include "module.h"
#include "stackframe.h"
#include "toolhelp.h"
#include "stddebug.h"
@@ -39,13 +40,15 @@
} LOCALARENA;
#define ARENA_HEADER_SIZE 4
+#define ARENA_HEADER( handle) ( ((handle) & ~3) - ARENA_HEADER_SIZE)
/* Arena types (stored in 'prev' field of the arena) */
#define LOCAL_ARENA_FREE 0
#define LOCAL_ARENA_FIXED 1
#define LOCAL_ARENA_MOVEABLE 3
-
+#define LMEM_NOCOMPACT 0x0010
+#define LMEM_NODISCARD 0x0020
typedef struct
{
@@ -93,6 +96,9 @@
#define ARENA_NEXT(ptr,arena) (ARENA_PTR(ptr,arena)->next)
#define ARENA_FLAGS(ptr,arena) (ARENA_PTR(ptr,arena)->prev & 3)
+ /* determine whether the handle belongs to a fixed or a moveable block */
+#define HANDLE_FIXED(handle) (((handle) & 3) == 0)
+#define HANDLE_MOVEABLE(handle) (((handle) & 3) == 2)
/***********************************************************************
* LOCAL_GetHeap
@@ -103,6 +109,7 @@
{
LOCALHEAPINFO *pInfo;
INSTANCEDATA *ptr = (INSTANCEDATA *)PTR_SEG_OFF_TO_LIN( ds, 0 );
+ dprintf_local( stddeb, "Heap at %04x\n", ptr->heap );
if (!ptr->heap) return 0;
pInfo = (LOCALHEAPINFO*)((char*)ptr + ptr->heap);
if (pInfo->magic != LOCAL_HEAP_MAGIC) return NULL;
@@ -138,6 +145,7 @@
next = pNext->next;
}
+ dprintf_local( stddeb, "Local_AddFreeBlock %04x, next %04x\n", block, next );
/* Insert the free block in the free-list */
pArena->free_prev = pNext->free_prev;
@@ -202,6 +210,7 @@
/* Remove the block from the free-list */
+ dprintf_local( stddeb, "Local_RemoveBlock\n");
pArena = ARENA_PTR( baseptr, block );
if ((pArena->prev & 3) == LOCAL_ARENA_FREE)
LOCAL_RemoveFreeBlock( baseptr, block );
@@ -229,6 +238,7 @@
LOCALHEAPINFO *pInfo = LOCAL_GetHeap( ds );
WORD arena;
+ if (!debugging_local) return;
if (!pInfo)
{
printf( "Local Heap corrupted! ds=%04x\n", ds );
@@ -266,7 +276,8 @@
}
if ((ARENA_PTR(ptr,pArena->next)->prev & ~3) != arena)
{
- printf( "*** arena->next->prev != arena\n" );
+ printf( "*** arena->next->prev != arena (%04x, %04x)\n",
+ pArena->next, ARENA_PTR(ptr,pArena->next)->prev);
break;
}
arena = pArena->next;
@@ -283,7 +294,8 @@
WORD heapInfoArena, freeArena, lastArena;
LOCALHEAPINFO *pHeapInfo;
LOCALARENA *pArena, *pFirstArena, *pLastArena;
-
+ NE_MODULE *pModule;
+
/* The initial layout of the heap is: */
/* - first arena (FIXED) */
/* - heap info structure (FIXED) */
@@ -295,14 +307,24 @@
ptr = PTR_SEG_OFF_TO_LIN( selector, 0 );
pHeapInfo = LOCAL_GetHeap(selector);
/* If there's already a local heap in this segment, */
- /* we simply return TRUE. Helps some programs, but */
- /* does not seem to be 100% correct yet (there are */
- /* still some "heap corrupted" messages in LocalAlloc */
+ /* we simply return TRUE. This helps some programs. */
if (pHeapInfo) {
dprintf_local(stddeb,"LocalInit: Heap %04x initialized twice.\n",selector);
if (debugging_local) LOCAL_PrintHeap(selector);
return TRUE;
}
+
+#if 0
+ /* Check if the segment is the DGROUP of a module */
+
+ if ((pModule = (NE_MODULE *)GlobalLock( GetExePtr( selector ) )))
+ {
+ SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
+ if (pModule->dgroup && (pSeg->selector == selector))
+ start = max( start, pSeg->minsize );
+ }
+#endif
+
start = LALIGN( max( start, sizeof(INSTANCEDATA) ) );
heapInfoArena = LALIGN(start + sizeof(LOCALARENA) );
freeArena = LALIGN( heapInfoArena + ARENA_HEADER_SIZE
@@ -335,6 +357,7 @@
pHeapInfo->items = 4;
pHeapInfo->first = start;
pHeapInfo->last = lastArena;
+ pHeapInfo->htable = 0;
pHeapInfo->hdelta = 0x20;
pHeapInfo->extra = 0x200;
pHeapInfo->minsize = lastArena - freeArena;
@@ -352,7 +375,7 @@
/* Initialise the last block */
pLastArena = ARENA_PTR( ptr, lastArena );
- pLastArena->prev = heapInfoArena | LOCAL_ARENA_FREE;
+ pLastArena->prev = freeArena | LOCAL_ARENA_FREE;
pLastArena->next = lastArena; /* this one */
pLastArena->size = LALIGN(sizeof(LOCALARENA));
pLastArena->free_prev = freeArena;
@@ -361,49 +384,80 @@
/* Store the local heap address in the instance data */
((INSTANCEDATA *)ptr)->heap = heapInfoArena + ARENA_HEADER_SIZE;
+ LOCAL_PrintHeap( selector );
return TRUE;
}
+/***********************************************************************
+ * LOCAL_Compact
+ */
+static WORD LOCAL_Compact( WORD ds, WORD minfree, WORD flags )
+{
+ if (flags & LMEM_NOCOMPACT) return 0;
+
+ return 0;
+}
/***********************************************************************
- * LOCAL_Alloc
- *
- * Implementation of LocalAlloc().
+ * LOCAL_FindFreeBlock
*/
-HLOCAL LOCAL_Alloc( WORD ds, WORD flags, WORD size )
+static HLOCAL LOCAL_FindFreeBlock( WORD ds, WORD size )
{
char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
LOCALHEAPINFO *pInfo;
LOCALARENA *pArena;
WORD arena;
- dprintf_local( stddeb, "LocalAlloc: %04x %d ds=%04x\n", flags, size, ds );
-
- /* Find a suitable free block */
-
if (!(pInfo = LOCAL_GetHeap( ds ))) {
- dprintf_local( stddeb, "LocalAlloc: Heap not found\n");
- LOCAL_PrintHeap(ds);
- return 0;
+ dprintf_local( stddeb, "Local_FindFreeBlock: Local heap not found\n" );
+ LOCAL_PrintHeap(ds);
+ return 0;
}
- size += ARENA_HEADER_SIZE;
- size = LALIGN( max( size, sizeof(LOCALARENA) ) );
+
arena = pInfo->first;
pArena = ARENA_PTR( ptr, arena );
- for (;;)
- {
- if (arena == pArena->free_next) {
- fprintf(stderr, "Local heap full\n");
- if (debugging_local) LOCAL_PrintHeap(ds);
- return 0; /* not found */
- }
+ while (arena != pArena->free_next) {
arena = pArena->free_next;
pArena = ARENA_PTR( ptr, arena );
- if (pArena->size >= size) break;
+ if (pArena->size >= size) return arena;
+ }
+ dprintf_local( stddeb, "Local_FindFreeBlock: not enough space\n" );
+ if (debugging_local) LOCAL_PrintHeap(ds);
+ return 0;
+}
+
+/***********************************************************************
+ * LOCAL_GetBlock
+ */
+static HLOCAL LOCAL_GetBlock( WORD ds, WORD size, WORD flags )
+{
+ char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
+ LOCALHEAPINFO *pInfo;
+ LOCALARENA *pArena;
+ WORD arena;
+
+ if (!(pInfo = LOCAL_GetHeap( ds ))) {
+ dprintf_local( stddeb, "Local_GetBlock: Local heap not found\n");
+ LOCAL_PrintHeap(ds);
+ return 0;
+ }
+
+ size += ARENA_HEADER_SIZE;
+ size = LALIGN( max( size, sizeof(LOCALARENA) ) );
+
+ /* Find a suitable free block */
+ arena = LOCAL_FindFreeBlock( ds, size );
+ if (arena == 0) {
+ LOCAL_Compact( ds, size, flags );
+ arena = LOCAL_FindFreeBlock( ds, size );
+ }
+ if (arena == 0) {
+ fprintf( stderr, "Local_GetBlock: not enough space!\n" );
}
+ dprintf_local( stddeb, "LOCAL_GetBlock size = %04x\n", size );
/* Make a block out of the free arena */
-
+ pArena = ARENA_PTR( ptr, arena );
if (pArena->size > size + LALIGN(sizeof(LOCALARENA)))
{
LOCAL_AddBlock( ptr, arena, arena+size );
@@ -412,97 +466,78 @@
}
LOCAL_RemoveFreeBlock( ptr, arena );
- dprintf_local( stddeb, "LocalAlloc: returning %04x\n",
- arena + ARENA_HEADER_SIZE );
+ dprintf_local( stddeb, "Local_GetBlock: arena at %04x\n", arena );
return arena + ARENA_HEADER_SIZE;
}
-
/***********************************************************************
- * LOCAL_ReAlloc
- *
- * Implementation of LocalReAlloc().
+ * LOCAL_NewHTable
*/
-HLOCAL LOCAL_ReAlloc( WORD ds, HLOCAL handle, WORD size, WORD flags )
+static BOOL LOCAL_NewHTable( WORD ds )
{
char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
LOCALHEAPINFO *pInfo;
- LOCALARENA *pArena, *pNext;
- WORD arena, newhandle;
+ HLOCAL handle;
- dprintf_local( stddeb, "LocalReAlloc: %04x %d %04x ds=%04x\n",
- handle, size, flags, ds );
- if (!(pInfo = LOCAL_GetHeap( ds ))) return 0;
- arena = handle - ARENA_HEADER_SIZE;
- pArena = ARENA_PTR( ptr, arena );
- if (flags & LMEM_MODIFY) {
- dprintf_local( stddeb, "LMEM_MODIFY set\n");
- return handle;
- }
- if (!size) size = 1;
- size = LALIGN( size );
-
- /* Check for size reduction */
-
- if (size < pArena->next - handle)
- {
- if (handle + size < pArena->next - LALIGN(sizeof(LOCALARENA)))
- {
- /* It is worth making a new free block */
- LOCAL_AddBlock( ptr, arena, handle + size );
- LOCAL_AddFreeBlock( ptr, handle + size );
- pInfo->items++;
- }
- dprintf_local( stddeb, "LocalReAlloc: returning %04x\n", handle );
- return handle;
+ dprintf_local( stddeb, "Local_NewHTable\n" );
+ if (!(pInfo = LOCAL_GetHeap( ds ))) {
+ dprintf_local( stddeb, "Local heap not found\n");
+ LOCAL_PrintHeap(ds);
+ return FALSE;
}
- /* Check if the next block is free */
-
- pNext = ARENA_PTR( ptr, pArena->next );
- if (((pNext->prev & 3) == LOCAL_ARENA_FREE) &&
- (size <= pNext->next - handle))
- {
- LOCAL_RemoveBlock( ptr, pArena->next );
- if (handle + size < pArena->next - LALIGN(sizeof(LOCALARENA)))
- {
- /* It is worth making a new free block */
- LOCAL_AddBlock( ptr, arena, handle + size );
- LOCAL_AddFreeBlock( ptr, handle + size );
- pInfo->items++;
- }
- dprintf_local( stddeb, "LocalReAlloc: returning %04x\n", handle );
- return handle;
- }
-
- /* Now we have to allocate a new block */
-
- newhandle = LOCAL_Alloc( ds, flags, size );
- if (!newhandle) return 0;
- memcpy( ptr + newhandle, ptr + handle, pArena->next - handle );
- LOCAL_Free( ds, handle );
- dprintf_local( stddeb, "LocalReAlloc: returning %04x\n", newhandle );
- return newhandle;
+ handle = LOCAL_GetBlock( ds, pInfo->hdelta*4 + 2, LMEM_FIXED );
+ if (handle == 0) return FALSE;
+ *(WORD *)(ptr + handle) = 0; /* no handles in this block yet */
+ pInfo->htable = handle;
+ return TRUE;
}
+/***********************************************************************
+ * LOCAL_GetNewHandle
+ */
+static HLOCAL LOCAL_GetNewHandle( WORD ds )
+{
+ char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
+ LOCALHEAPINFO *pInfo;
+ WORD count;
+
+ if (!(pInfo = LOCAL_GetHeap( ds ))) {
+ dprintf_local( stddeb, "LOCAL_GetNewHandle: Local heap not found\n");
+ LOCAL_PrintHeap(ds);
+ return 0;
+ }
+ /* Check if we need a new handle table */
+ if (pInfo->htable == 0)
+ if (!LOCAL_NewHTable( ds )) return 0;
+ if (*(WORD *)(ptr + pInfo->htable) == pInfo->hdelta)
+ if (!LOCAL_NewHTable( ds )) return 0;
+
+ /* increase count */
+ count = (*(WORD *)(ptr + pInfo->htable))++;
+ dprintf_local( stddeb, "Local_GetNewHandle: %04x\n", pInfo->htable + 2 + 4*count );
+ return pInfo->htable + 2 + 4*count;
+}
/***********************************************************************
- * LOCAL_Free
- *
- * Implementation of LocalFree().
+ * LOCAL_FreeArena
*/
-HLOCAL LOCAL_Free( WORD ds, HLOCAL handle )
+HLOCAL LOCAL_FreeArena( WORD ds, WORD arena )
{
char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
LOCALHEAPINFO *pInfo;
LOCALARENA *pArena, *pPrev, *pNext;
- WORD arena;
- dprintf_local( stddeb, "LocalFree: %04x ds=%04x\n", handle, ds );
- if (!(pInfo = LOCAL_GetHeap( ds ))) return handle;
- arena = handle - ARENA_HEADER_SIZE;
+ dprintf_local( stddeb, "LocalFreeArena: %04x ds=%04x\n", arena, ds );
+ if (!(pInfo = LOCAL_GetHeap( ds ))) return arena;
+
pArena = ARENA_PTR( ptr, arena );
- if ((pArena->prev & 3) == LOCAL_ARENA_FREE) return handle;
+ if ((pArena->prev & 3) == LOCAL_ARENA_FREE) {
+ /* shouldn't happen */
+ fprintf( stderr, "LocalFreeArena: Trying to free a block twice!\n" );
+ LOCAL_PrintHeap( ds );
+ return arena;
+ }
/* Check if we can merge with the previous block */
@@ -533,6 +568,153 @@
/***********************************************************************
+ * LOCAL_Free
+ *
+ * Implementation of LocalFree().
+ */
+HLOCAL LOCAL_Free( WORD ds, HLOCAL handle )
+{
+ char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
+ WORD arena;
+
+ dprintf_local( stddeb, "LocalFree: %04x ds=%04x\n", handle, ds );
+
+ if (HANDLE_FIXED( handle )) {
+ arena = ARENA_HEADER( handle );
+ } else {
+ arena = ARENA_HEADER( *(WORD *)(ptr + handle) );
+ dprintf_local( stddeb, "LocalFree: real block at %04x\n", arena);
+ }
+ arena = LOCAL_FreeArena( ds, arena );
+ if (arena != 0) return handle; /* couldn't free it */
+ return 0;
+}
+
+
+/***********************************************************************
+ * LOCAL_Alloc
+ *
+ * Implementation of LocalAlloc().
+ */
+HLOCAL LOCAL_Alloc( WORD ds, WORD flags, WORD size )
+{
+ char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
+ HLOCAL handle;
+
+ dprintf_local( stddeb, "LocalAlloc: %04x %d ds=%04x\n", flags, size, ds );
+
+ if (flags & LMEM_MOVEABLE) {
+ LOCALHANDLEENTRY *plhe;
+ HLOCAL hmem;
+
+ hmem = LOCAL_GetBlock( ds, size + 2, flags );
+ if (hmem == 0) return 0;
+ handle = LOCAL_GetNewHandle( ds );
+ if (handle == 0) {
+ fprintf( stderr, "LocalAlloc: couldn't get handle\n");
+ LOCAL_FreeArena( ds, ARENA_HEADER(hmem) );
+ return 0;
+ }
+ *(WORD *)(ptr + hmem) = handle;
+ plhe = (LOCALHANDLEENTRY *)(ptr + handle);
+ plhe->addr = hmem + 2;
+ plhe->lock = 0;
+ } else {
+ handle = LOCAL_GetBlock( ds, size, flags );
+ }
+ return handle;
+}
+
+
+/***********************************************************************
+ * LOCAL_ReAlloc
+ *
+ * Implementation of LocalReAlloc().
+ */
+HLOCAL LOCAL_ReAlloc( WORD ds, HLOCAL handle, WORD size, WORD flags )
+{
+ char *ptr = PTR_SEG_OFF_TO_LIN( ds, 0 );
+ LOCALHEAPINFO *pInfo;
+ LOCALARENA *pArena, *pNext;
+ WORD arena, newhandle, blockhandle, nextarena;
+
+ dprintf_local( stddeb, "LocalReAlloc: %04x %d %04x ds=%04x\n",
+ handle, size, flags, ds );
+ if (!(pInfo = LOCAL_GetHeap( ds ))) return 0;
+
+ if (HANDLE_FIXED( handle )) {
+ blockhandle = handle;
+ } else {
+ size += 2;
+ blockhandle = *(WORD *)(ptr + handle);
+ dprintf_local( stddeb, " blockhandle %04x (%04x)\n", blockhandle,
+ *(WORD *)(ptr + blockhandle - 2));
+ }
+ arena = ARENA_HEADER( blockhandle );
+ dprintf_local( stddeb, "LocalReAlloc: arena is %04x\n", arena );
+ pArena = ARENA_PTR( ptr, arena );
+
+ if (flags & LMEM_MODIFY) {
+ dprintf_local( stddeb, "LMEM_MODIFY set\n");
+ return handle;
+ }
+ if (!size) size = 1;
+ size = LALIGN( size );
+ nextarena = LALIGN(blockhandle + size);
+
+ /* Check for size reduction */
+
+ if (nextarena < pArena->next)
+ {
+ if (nextarena < pArena->next - LALIGN(sizeof(LOCALARENA)))
+ {
+ dprintf_local( stddeb, "size reduction, making new free block\n");
+ /* It is worth making a new free block */
+ LOCAL_AddBlock( ptr, arena, nextarena );
+ LOCAL_AddFreeBlock( ptr, nextarena );
+ pInfo->items++;
+ }
+ dprintf_local( stddeb, "LocalReAlloc: returning %04x\n", handle );
+ return handle;
+ }
+
+ /* Check if the next block is free */
+
+ pNext = ARENA_PTR( ptr, pArena->next );
+ if (((pNext->prev & 3) == LOCAL_ARENA_FREE) &&
+ (nextarena <= pNext->next))
+ {
+ LOCAL_RemoveBlock( ptr, pArena->next );
+ if (nextarena < pArena->next - LALIGN(sizeof(LOCALARENA)))
+ {
+ dprintf_local( stddeb, "size increase, making new free block\n");
+ /* It is worth making a new free block */
+ LOCAL_AddBlock( ptr, arena, nextarena );
+ LOCAL_AddFreeBlock( ptr, nextarena );
+ pInfo->items++;
+ }
+ dprintf_local( stddeb, "LocalReAlloc: returning %04x\n", handle );
+ return handle;
+ }
+
+ /* Now we have to allocate a new block */
+
+ newhandle = LOCAL_GetBlock( ds, size, flags );
+ if (newhandle == 0) return 0;
+ memcpy( ptr + newhandle, ptr + (arena + ARENA_HEADER_SIZE), size );
+ LOCAL_FreeArena( ds, arena );
+ if (HANDLE_MOVEABLE( handle )) {
+ newhandle += 2;
+ dprintf_local( stddeb, "LocalReAlloc: fixing handle\n");
+ *(WORD *)(ptr + handle) = newhandle;
+ newhandle = handle;
+ }
+ dprintf_local( stddeb, "LocalReAlloc: returning %04x\n", newhandle );
+ return newhandle;
+}
+
+
+/***********************************************************************
* LOCAL_Size
*
* Implementation of LocalSize().
@@ -589,6 +771,11 @@
*/
WORD LocalLock( HLOCAL handle )
{
+ char *ptr = PTR_SEG_OFF_TO_LIN( CURRENT_DS, 0 );
+
+ if (HANDLE_MOVEABLE(handle)) {
+ handle = *(WORD *)(ptr + handle);
+ }
return handle;
}
@@ -616,7 +803,12 @@
*/
HLOCAL LocalHandle( WORD addr )
{
+ char *ptr = PTR_SEG_OFF_TO_LIN( CURRENT_DS, 0 );
+
dprintf_local( stddeb, "LocalHandle: %04x\n", addr );
+ if (HANDLE_MOVEABLE( addr )) {
+ addr = *(WORD *)(ptr + addr - 2);
+ }
return addr;
}