Release 0.1.0

WHAT'S NEW with version 0.1.0:
    - Integrated patches from Alexandre.
    - Minor bug fix in if1632.S

WHAT'S NEW with version 0.0.5:
    - Patches from Alexandre Julliard.  Some integration with Tcl.
    - Generic interface for callback procedures.  This will allow
      callbacks into DLLs.
    - MakeProcInstance() has been implemented but untested.

WHAT'S NEW with version 0.0.4:
    - Eric Youngdale modified wine.c and selector.c to allow loading
      of Windows DLLs.
    - Added global memory allocation routines (GlobalAlloc, GlobalFree,
      and GlobalLock)
    - Bitmap resource loading into global memory.
diff --git a/global.c b/global.c
new file mode 100644
index 0000000..3ef21ee
--- /dev/null
+++ b/global.c
@@ -0,0 +1,316 @@
+static char RCSId[] = "$Id: global.c,v 1.2 1993/07/04 04:04:21 root Exp root $";
+static char Copyright[] = "Copyright  Robert J. Amstadt, 1993";
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "prototypes.h"
+#include "heap.h"
+#include "segmem.h"
+
+/*
+ * Global memory pool descriptor.
+ *
+ * handle  = 0, this descriptor contains the address of a free pool.
+ *        != 0, this describes an allocated block.
+ *
+ * sequence = 0, this is not a huge block
+ *          > 0, this is a portion of a huge block
+ *          =-1, this is a free segment
+ *
+ * addr	      - address of this memory block.
+ *
+ * length     - used to maintain huge blocks.
+ *
+ */
+typedef struct global_mem_desc_s
+{
+    struct global_mem_desc_s *next;
+    struct global_mem_desc_s *prev;
+    unsigned short handle;
+    short sequence;
+    void *addr;
+    int length;
+} GDESC;
+
+GDESC *GlobalList = NULL;
+
+/**********************************************************************
+ *					GLOBAL_GetFreeSegments
+ */
+GDESC *
+GLOBAL_GetFreeSegments(unsigned int flags, int n_segments)
+{
+    struct segment_descriptor_s *s;
+    GDESC *g;
+    GDESC *g_start;
+    GDESC *g_prev;
+    int count, i;
+
+    /*
+     * Try to find some empty segments in our list.
+     */
+    count = 0;
+    for (g = GlobalList; g != NULL && count != n_segments; g = g->next)
+    {
+	if ((int) g->sequence == -1)
+	{
+	    if (count > 0)
+	    {
+		if (g->prev->handle + 8 != g->handle)
+		    count = 0;
+		else
+		    count++;
+	    }
+	    else
+	    {
+		g_start = g;
+		count = 1;
+	    }
+	}
+	else if (count)
+	    count = 0;
+    }
+
+    /*
+     * If we couldn't find enough segments, then we need to create some.
+     */
+    if (count != n_segments)
+    {
+	/*
+	 * Find list tail.
+	 */
+	g_prev = NULL;
+	for (g = GlobalList; g != NULL; g = g->next)
+	    g_prev = g;
+
+	/*
+	 * Allocate segments.
+	 */
+	for (count = 0; count < n_segments; count++)
+	{
+	    s = GetNextSegment(flags, 0x10000);
+	    if (s == NULL)
+		return NULL;
+
+	    g = (GDESC *) malloc(sizeof(*g));
+	    
+	    g->prev = g_prev;
+	    g->next = NULL;
+	    g->handle = s->selector;
+	    g->sequence = -1;
+	    g->addr = s->base_addr;
+	    g->length = s->length;
+
+	    free(s);
+
+	    if (count == 0)
+		g_start = g;
+
+	    if (g_prev != NULL)
+	    {
+		g_prev->next = g;
+		g->prev = g_prev;
+	    }
+	    else
+		GlobalList = g;
+	}
+    }
+
+    /*
+     * We have all of the segments we need.  Let's adjust their contents.
+     */
+    g = g_start;
+    for (i = 0; i < n_segments; i++, g = g->next)
+    {
+	g->sequence = i + 1;
+	g->length = n_segments;
+    }
+
+    return g_start;
+}
+
+/**********************************************************************
+ *					GLOBAL_Alloc
+ */
+unsigned int
+GLOBAL_Alloc(unsigned int flags, unsigned long size)
+{
+    GDESC *g;
+    GDESC *g_prev;
+    void *m;
+    int i;
+
+    /*
+     * If this block is fixed or very big we need to allocate entire
+     * segments.
+     */
+    if (size > 0x8000 || !(flags & GLOBAL_FLAGS_MOVEABLE))
+    {
+	int segments = (size >> 16) + 1;
+
+	g = GLOBAL_GetFreeSegments(flags, segments);
+	if (g == NULL)
+	    return 0;
+	else
+	    return g->handle;
+    }
+    /*
+     * Otherwise we just need a little piece of a segment.
+     */
+    else
+    {
+	/*
+	 * Try to allocate from active free lists.
+	 */
+	for (g = GlobalList; g != NULL; g = g->next)
+	{
+	    if (g->handle == 0 && g->sequence == 0)
+	    {
+		m = HEAP_Alloc((MDESC **) g->addr, 0, size);
+		if (m != NULL)
+		    break;
+	    }
+	}
+
+	/*
+	 * If we couldn't get the memory there, then we need to create
+	 * a new free list.
+	 */
+	if (m == NULL)
+	{
+	    g = GLOBAL_GetFreeSegments(0, 1);
+	    if (g == NULL)
+		return 0;
+
+	    g->handle = 0;
+	    g->sequence = 0;
+	    HEAP_Init((MDESC **) g->addr, (MDESC **) g->addr + 1, 
+		      0x10000 - sizeof(MDESC **));
+	    m = HEAP_Alloc((MDESC **) g->addr, 0, size);
+	    if (m == NULL)
+		return 0;
+	}
+
+	/*
+	 * We have a new block.  Let's create a GDESC entry for it.
+	 */
+	g_prev = NULL;
+	i = 0;
+	for (g = GlobalList; g != NULL; g = g->next, i++)
+	    g_prev = g;
+
+	g = malloc(sizeof(*g));
+	if (g == NULL)
+	    return 0;
+
+	g->handle = i << 3;
+	g->sequence = 0;
+	g->addr = m;
+	g->length = size;
+	g->next = NULL;
+
+	if (g_prev != NULL)
+	{
+	    g_prev->next = g;
+	    g->prev = g_prev;
+	}
+	else
+	{
+	    GlobalList = g;
+	    g->prev = NULL;
+	}
+	
+	return g->handle;
+    }
+}
+
+/**********************************************************************
+ *					GLOBAL_Free
+ *
+ * Windows programs will pass a handle in the "block" parameter, but
+ * this function will also accept a 32-bit address.
+ */
+unsigned int
+GLOBAL_Free(unsigned int block)
+{
+    GDESC *g;
+
+    if (block == 0)
+	return 0;
+
+    /*
+     * Find GDESC for this block.
+     */
+    if (block & 0xffff0000)
+    {
+	for (g = GlobalList; g != NULL; g = g->next)
+	    if (g->handle > 0 && (unsigned int) g->addr == block)
+		break;
+    }
+    else
+    {
+	for (g = GlobalList; g != NULL; g = g->next)
+	    if (g->handle == block)
+		break;
+    }
+    if (g == NULL)
+	return block;
+
+    /*
+     * If the sequence number is zero then use HEAP_Free to deallocate
+     * memory, and throw away this descriptor.
+     */
+    if (g->sequence == 0)
+    {
+	HEAP_Free((MDESC **) (block & 0xffff0000), (void *) block);
+
+	if (g->prev != NULL)
+	    g->prev->next = g->next;
+	else
+	    GlobalList = g->next;
+	
+	if (g->next != NULL)
+	    g->next->prev = g->prev;
+
+	free(g);
+    }
+    
+    /*
+     * Otherwise just mark these descriptors as free.
+     */
+    else
+    {
+	int i, limit;
+	
+	g->length;
+	for (i = 0; i < limit; i++)
+	{
+	    g->sequence = -1;
+	    g->length = 0x10000;
+	}
+    }
+
+    return 0;
+}
+
+/**********************************************************************
+ *					GLOBAL_Lock
+ *
+ */
+void *
+GLOBAL_Lock(unsigned int block)
+{
+    GDESC *g;
+
+    if (block == 0)
+	return 0;
+
+    /*
+     * Find GDESC for this block.
+     */
+    for (g = GlobalList; g != NULL; g = g->next)
+	if (g->handle == block)
+	    return g->addr;
+
+    return NULL;
+}