Release 961222

Sun Dec 22 13:30:18 1996  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [graphics/metafiledrv/init.c] [graphisc/metafiledrv/mapping.c]
	Added mapping functions.

	* [if1632/gdi.spec] [objects/*.c] [include/windows.h]
	Added a lot of Win32 functions.

	* [memory/heap.c]
	Added HEAP_strdupAtoW and HEAP_strdupWtoA.

	* [misc/lstr.c] [memory/string.c]
	Moved OEM<->Ansi conversion to string.c. Fixed a couple of bugs.

	* [object/font.c]
	Avoid uppercasing font names.

	* [windows/hook.c]
	Set ds = ss before calling hook procedure.

Sat Dec 21 21:44:17 1996  Alex Korobka <alex@trantor.pharm.sunysb.edu>

	* [objects/color.c]
	Use colors allocated by other clients. 

	* [windows/caret.c]
	Set default blink time to 500.

	* [windows/win.c] [windows/event.c]
	Delete X context before XDestroyWindow().

	* [windows/keyboard.c]
	Fixed GetKeyState() once more.

Fri Dec 20 08:26:33 1996  Eric Youngdale <eric@sub2304.jic.com>

	* [debugger/*.c]
	Lots of built-in debugger improvements: parse Win32 EXEs debug
 	information, display local variables, source files and line
 	numbers, get symbols directly from the Wine executable, etc.

Tue Dec 17 22:39:42 1996  Philippe De Muyter  <phdm@info.ucl.ac.be>

	* [misc/winsock_async.c]
 	Extern declaration added for h_errno.

Tue Dec 17 21:29:34 1996  Albrecht Kleine  <kleine@ak.sax.de>

	* [windows/message.c]
	Added two more CBT hook calls: HCBT_CLICKSKIPPED/HCBT_KEYSKIPPED.
diff --git a/debugger/stack.c b/debugger/stack.c
index bbf9033..9ac2ea2 100644
--- a/debugger/stack.c
+++ b/debugger/stack.c
@@ -2,13 +2,35 @@
  * Debugger stack handling
  *
  * Copyright 1995 Alexandre Julliard
+ * Copyright 1996 Eric Youngdale
  */
 
 #include <stdio.h>
+#include <malloc.h>
+#include "xmalloc.h"
 #include "windows.h"
 #include "debugger.h"
 
 
+/*
+ * We keep this info for each frame, so that we can
+ * find local variable information correctly.
+ */
+struct bt_info
+{
+  unsigned int	     eip;
+  unsigned int	     ebp;
+  struct name_hash * frame;
+};
+
+static int nframe;
+static struct bt_info * frames = NULL;
+int curr_frame;
+static char * reg_name[] =
+{
+  "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
+};
+
 typedef struct
 {
     WORD bp;
@@ -66,19 +88,45 @@
     if (SS_reg(DEBUG_context) == WINE_DATA_SELECTOR)  /* 32-bit mode */
     {
         addr.seg = 0;
-        fprintf(stderr,"%d ",frameno++);
-        addr.off = EIP_reg(DEBUG_context);
-        DEBUG_PrintAddress( &addr, 32 );
-        fprintf( stderr, "\n" );
         addr.off = EBP_reg(DEBUG_context);
+	nframe = 1;
         while (addr.off)
         {
             FRAME32 *frame = (FRAME32 *)addr.off;
             if (!DBG_CHECK_READ_PTR( &addr, sizeof(FRAME32) )) return;
             if (!frame->ip) break;
-            fprintf(stderr,"%d ",frameno++);
+            addr.off = frame->bp;
+	    nframe++;
+        }
+	if( frames != NULL )
+	  {
+	    free(frames);
+	  }
+
+	frames = (struct bt_info *) xmalloc(nframe 
+					      * sizeof(struct bt_info) );
+        fprintf(stderr,"%s%d ",(curr_frame == 0 ? "=>" : "  "), frameno++);
+        addr.off = EIP_reg(DEBUG_context);
+	frames[0].eip = addr.off;
+        frames[0].frame = DEBUG_PrintAddress( &addr, 32, TRUE );
+        fprintf( stderr, "\n" );
+        addr.off = EBP_reg(DEBUG_context);
+
+	frames[0].ebp = addr.off;
+
+        while (addr.off)
+        {
+            FRAME32 *frame = (FRAME32 *)addr.off;
+            if (!DBG_CHECK_READ_PTR( &addr, sizeof(FRAME32) )) return;
+            if (!frame->ip) break;
+            fprintf(stderr,"%s%d ", (frameno == curr_frame ? "=>" : "  "),
+		    frameno);
             addr.off = frame->ip;
-            DEBUG_PrintAddress( &addr, 32 );
+	    frames[frameno].eip = addr.off;
+	    frames[frameno].ebp = frame->bp;
+            frames[frameno].frame = DEBUG_PrintAddressAndArgs( &addr, 32, 
+							frame->bp, TRUE );
+	    frameno++;
             fprintf( stderr, "\n" );
             addr.off = frame->bp;
         }
@@ -94,7 +142,7 @@
       fprintf( stderr,"%d ", frameno++ );
       addr.seg = cs;
       addr.off = IP_reg(DEBUG_context);
-      DEBUG_PrintAddress( &addr, 16 );
+      DEBUG_PrintAddress( &addr, 16, TRUE );
       fprintf( stderr, "\n" );
       addr.seg = ss;
       addr.off = BP_reg(DEBUG_context) & ~1;
@@ -107,7 +155,7 @@
           fprintf( stderr,"%d ", frameno++ );
           addr.seg = cs;
           addr.off = frame->ip;
-          DEBUG_PrintAddress( &addr, 16 );
+          DEBUG_PrintAddress( &addr, 16, TRUE );
           fprintf( stderr, "\n" );
           addr.seg = ss;
           addr.off = frame->bp & ~1;
@@ -115,3 +163,166 @@
   }
   fprintf( stderr, "\n" );
 }
+
+/***********************************************************************
+ *           DEBUG_GetSymbolValue
+ *
+ * Get the address of a named symbol from the current stack frame.
+ */
+BOOL32 DEBUG_GetStackSymbolValue( const char * name, DBG_ADDR *addr )
+{
+  struct name_hash * curr_func;
+  int		     i;
+
+  /*
+   * If we don't have a valid backtrace, then just return.
+   */
+  if( frames == NULL )
+    {
+      return FALSE;
+    }
+
+  curr_func = frames[curr_frame].frame;
+
+  /*
+   * If we don't know what the current function is, then we also have
+   * nothing to report here.
+   */
+  if( curr_func == NULL )
+    {
+      return FALSE;
+    }
+
+  for(i=0; i < curr_func->n_locals; i++ )
+    {
+      /*
+       * Test the range of validity of the local variable.  This
+       * comes up with RBRAC/LBRAC stabs in particular.
+       */
+      if(    (curr_func->local_vars[i].pc_start != 0)
+	  && ((frames[curr_frame].eip - curr_func->addr.off) 
+	      < curr_func->local_vars[i].pc_start) )
+	{
+	  continue;
+	}
+
+      if(    (curr_func->local_vars[i].pc_end != 0)
+	  && ((frames[curr_frame].eip - curr_func->addr.off) 
+	      > curr_func->local_vars[i].pc_end) )
+	{
+	  continue;
+	}
+
+      if( strcmp(name, curr_func->local_vars[i].name) == 0 )
+	{
+	  /*
+	   * OK, we found it.  Now figure out what to do with this.
+	   */
+	  if( curr_func->local_vars[i].regno != 0 )
+	    {
+	      /*
+	       * Register variable.  We don't know how to treat
+	       * this yet.
+	       */
+	      return FALSE;
+	    }
+
+	  addr->seg = 0;
+	  addr->off = frames[curr_frame].ebp + curr_func->local_vars[i].offset;
+
+	  return TRUE;
+	}
+    }
+  return FALSE;
+}
+
+int
+DEBUG_SetFrame(int newframe)
+{
+  int		rtn = FALSE;
+  /*
+   * Nothing for now.  Add support later.
+   */
+
+  curr_frame = newframe;
+  if( curr_frame < 0 )
+    {
+      curr_frame = 0;
+    }
+
+  if( curr_frame >= nframe )
+    {
+      curr_frame = nframe - 1;
+    }
+
+  rtn = TRUE;
+  return (rtn);
+}
+
+int
+DEBUG_InfoLocals()
+{
+  struct name_hash * curr_func;
+  int		     i;
+  int		rtn = FALSE;
+  unsigned	int * ptr;
+
+  /*
+   * If we don't have a valid backtrace, then just return.
+   */
+  if( frames == NULL )
+    {
+      return FALSE;
+    }
+
+  curr_func = frames[curr_frame].frame;
+
+  /*
+   * If we don't know what the current function is, then we also have
+   * nothing to report here.
+   */
+  if( curr_func == NULL )
+    {
+      return FALSE;
+    }
+
+  for(i=0; i < curr_func->n_locals; i++ )
+    {
+      /*
+       * Test the range of validity of the local variable.  This
+       * comes up with RBRAC/LBRAC stabs in particular.
+       */
+      if(    (curr_func->local_vars[i].pc_start != 0)
+	  && ((frames[curr_frame].eip - curr_func->addr.off) 
+	      < curr_func->local_vars[i].pc_start) )
+	{
+	  continue;
+	}
+
+      if(    (curr_func->local_vars[i].pc_end != 0)
+	  && ((frames[curr_frame].eip - curr_func->addr.off) 
+	      > curr_func->local_vars[i].pc_end) )
+	{
+	  continue;
+	}
+      
+      if( curr_func->local_vars[i].offset == 0 )
+	{
+	  fprintf(stderr, "%s:%s optimized into register $%s \n",
+		  curr_func->name, curr_func->local_vars[i].name,
+		  reg_name[curr_func->local_vars[i].regno]);
+	}
+      else
+	{
+	  ptr = (unsigned int *) (frames[curr_frame].ebp 
+				   + curr_func->local_vars[i].offset);
+	  fprintf(stderr, "%s:%s == 0x%8.8x\n",
+		  curr_func->name, curr_func->local_vars[i].name,
+		  *ptr);
+	}
+    }
+
+  rtn = TRUE;
+
+  return (rtn);
+}