Release 970112

Sat Jan 11 18:17:59 1997  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [controls/menu.c]
	Updated to new Win32 types.

	* [controls/listbox.c]
	Fixed Winfile extended selection bug.

	* [files/directory.c]
	Changed DIR_SearchPath to return both long and short file names.

	* [files/dos_fs.c]
	Implemented VFAT ioctl to retrieve the original short filenames
	from a VFAT filesystem (Linux only for now).
	Replaced DOSFS_GetUnixFileName()/DOSFS_GetDosTrueName() by
	DOS_GetFullName().
	Properly implemented GetShortPathName() and GetFullPathName().
	Made all functions re-entrant.

	* [files/file.c] [misc/main.c]
	Replaced -allowreadonly option by -failreadonly. The default is
	now to report success when opening a read-only file for writing.

	* [objects/metafile.c]
	Fixed bug in DIB bitmaps pointer calculation.

	* [scheduler/process.c]
	Implemented environment strings and Get/SetStdHandle with process
 	environment block.

	* [tools/build.c]
	Rewrote BuildContext32() to avoid instructions that may not be
	supported by all assemblers.
	
Fri Jan 10 17:11:09 1997  David Faure  <david.faure@ifhamy.insa-lyon.fr>

	* [windows/event.c]
	Created table keyc2vkey, which associate a vkey(+extended bit) to
	any keycode. Changed EVENT_event_to_vkey to use this table to
	return the correct vkey. Changed EVENT_ToAscii to get the keycode
	from this table too.  Assigned OEM specific vkeys arbitrarily.

Fri Jan 10 09:26:17 1997  John Harvey <john@division.co.uk>

	* [misc/winsock.c] [misc/winsoc_async.c]
        Fixed svr4 header files.
        Changed bzero() to memset().

	* [tools/fnt2bdf.c]
        Removed bcopy() and used memcpy() instead.

	* [debugger/msc.c]
        Include string.h instead of strings.h

	* [debugger/stabs.c]
        Include string.h instead of strings.h.
        Define __ELF__ for svr4 systems.

	* [loader/signal.c]
        Use wait() instead of wait4() which doesnt exist on Unixware.

	* [memory/global.c]
        Use sysconf() instead of getpagesize() for svr4 systems.

Thu Jan  9 21:07:20 1997  Robert Pouliot <krynos@clic.net>

	* [Make.rules.in] [Makefile.in] [make_os2.sh] [rc/Makefile.in]
	  [tools/Makefile.in] [documentation/wine_os2.txt]
	Patches for OS/2 support. Note that it doesn't compile yet.

Tue Jan  7 20:03:53 1997  Eric Youngdale <eric@sub2304.jic.com>

	* [debugger/*]
	Many more debugger improvements (see debugger/README for details).

Tue Jan  7 15:12:21 1997  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>

	* [windows/graphics.c] [objects/text.c] [graphics/x11drv/*]
	  [graphics/metafiledrv/*]
	Moved some device dependent code into the resp. subdirs.

	* [include/gdi.h] [include/metafiledrv.h] [include/x11drv.h]
	Prototypes added,
	DC_FUNCTIONS: GetPixel added, some unnecessary functions removed.

	* [objects/region.c]
	CreatePolyPolygonRgn32 added.

	* [files/dos_fs.c]
	QueryDosDevice added.

	* [misc/lstr.c]
	FormatMessage: broken heap management fixed.

	* [scheduler/process.c] [scheduler/thread.c]
	Get/SetThreadPriority/PriorityClass added.

Mon Jan  6 21:55:30 1997  Philippe De Muyter  <phdm@info.ucl.ac.be>

	* [misc/keyboard.c]
	ToAscii : Use EVENT_ToAscii instead.

	* [windows/event.c]
	keypad_key : Do not convert XK_Mode_switch to VK_MENU; recognize
	keypad cursor keys.
	EVENT_event_to_vkey : New function, to transform a X keycode
	into a MSwin vkey + extended bit.
	EVENT_ToAscii : New function, to transform a vkey + extended bit
	(+ key state table) into ascii char(s), using XLookupString, and
	recognizing dead chars.
	EVENT_key : Transform AltGr into Ctrl+Alt sequence; call
	EVENT_event_to_vkey for keycode to vkey conversion; fixed
	previous, context and extended bits.

	* [windows/keyboard.c]
	Include stddebug.h, to get -debugmsg messages.
	GetKeyState : Handle VK_MBUTTON case.
	GetKeyboardState, SetKeyboardState : Debugging messages added.

	* [windows/message.c]
	TranslateMessage : Handle dead chars.

Mon Jan  6 20:10:11 1997  Dominik Strasser  <bm424953@muenchen.org>

	* [if1632/crtdll.spec] [misc/crtdll.c]
	C++ functions new/delete/set_new_handler implemented.

Mon Jan  6 15:48:15 1997 Frans van Dorsselaer <dorssel@rulhmpc49.LeidenUniv.nl>

	* [controls/edit.c] [include/windows.h]
	Moved the edit control to 32 bits.
	Included new (win95) message definitions in windows.h
	Implemented EM_SCROLLCARET, EM_SETMARGINS, EM_GETMARGINS,
	EM_GETLIMITTEXT, EM_POSFROMCHAR, EM_CHARFROMPOS.
	Broke EM_SETWORDBREAKPROC (internal wordwrap still works).
	Fixed some bugs, introduced a couple of others.
	Text buffer is now initially in 32-bit heap.

	* [controls/EDIT.TODO] [controls/combo.c] [controls/widgets.c]
	  [if1632/wprocs.spec] [library/miscstubs.c] [windows/defdlg.c]
	  [misc/commdlg.c]
	Updated to work with 32-bit edit control.

Sat Jan  4 22:07:27 1997  O.Flebbe  <O.Flebbe@science-computing.uni-tuebingen.de>

	* [loader/pe_image.c]
	Use mmap rather then malloc. Better workaround for clean
	segments.
diff --git a/debugger/break.c b/debugger/break.c
index eb97f6c..5cf164f 100644
--- a/debugger/break.c
+++ b/debugger/break.c
@@ -14,15 +14,17 @@
 
 #define INT3          0xcc   /* int 3 opcode */
 
-#define MAX_BREAKPOINTS 25
+#define MAX_BREAKPOINTS 100
 
 typedef struct
 {
-    DBG_ADDR    addr;
-    BYTE        addrlen;
-    BYTE        opcode;
-    BOOL16      enabled;
-    BOOL16      in_use;
+    DBG_ADDR      addr;
+    BYTE          addrlen;
+    BYTE          opcode;
+    BOOL16        enabled;
+    WORD	  skipcount;
+    BOOL16        in_use;
+    struct expr * condition;
 } BREAKPOINT;
 
 static BREAKPOINT breakpoints[MAX_BREAKPOINTS];
@@ -65,7 +67,7 @@
  * Determine if the instruction at CS:EIP is an instruction that
  * we need to step over (like a call or a repetitive string move).
  */
-static BOOL32 DEBUG_IsStepOverInstr(void)
+static BOOL32 DEBUG_IsStepOverInstr()
 {
     BYTE *instr = (BYTE *)PTR_SEG_OFF_TO_LIN( CS_reg(&DEBUG_context),
                                               EIP_reg(&DEBUG_context) );
@@ -126,6 +128,31 @@
 
 
 /***********************************************************************
+ *           DEBUG_IsFctReturn
+ *
+ * Determine if the instruction at CS:EIP is an instruction that
+ * is a function return.
+ */
+BOOL32 DEBUG_IsFctReturn(void)
+{
+    BYTE *instr = (BYTE *)PTR_SEG_OFF_TO_LIN( CS_reg(&DEBUG_context),
+                                              EIP_reg(&DEBUG_context) );
+
+    for (;;)
+    {
+        switch(*instr)
+        {
+	case 0xc2:
+	case 0xc3:
+	  return TRUE;
+        default:
+            return FALSE;
+        }
+    }
+}
+
+
+/***********************************************************************
  *           DEBUG_SetBreakpoints
  *
  * Set or remove all the breakpoints.
@@ -205,6 +232,7 @@
     breakpoints[num].opcode  = *p;
     breakpoints[num].enabled = TRUE;
     breakpoints[num].in_use  = TRUE;
+    breakpoints[num].skipcount = 0;
     fprintf( stderr, "Breakpoint %d at ", num );
     DEBUG_PrintAddress( &breakpoints[num].addr, breakpoints[num].addrlen,
 			TRUE );
@@ -226,6 +254,7 @@
     }
     breakpoints[num].enabled = FALSE;
     breakpoints[num].in_use  = FALSE;
+    breakpoints[num].skipcount = 0;
 }
 
 
@@ -242,6 +271,7 @@
         return;
     }
     breakpoints[num].enabled = enable;
+    breakpoints[num].skipcount = 0;
 }
 
 
@@ -263,6 +293,12 @@
             DEBUG_PrintAddress( &breakpoints[i].addr, breakpoints[i].addrlen,
 				TRUE);
             fprintf( stderr, "\n" );
+	    if( breakpoints[i].condition != NULL )
+	      {
+		fprintf(stderr, "\t\tstop when  ");
+ 		DEBUG_DisplayExpr(breakpoints[i].condition);
+		fprintf(stderr, "\n");
+	      }
         }
     }
 }
@@ -274,10 +310,12 @@
  * Determine if we should continue execution after a SIGTRAP signal when
  * executing in the given mode.
  */
-BOOL32 DEBUG_ShouldContinue( enum exec_mode mode )
+BOOL32 DEBUG_ShouldContinue( enum exec_mode mode, int * count )
 {
     DBG_ADDR addr;
+    DBG_ADDR cond_addr;
     int bpnum;
+    struct list_id list;
 
       /* If not single-stepping, back up over the int3 instruction */
     if (!(EFL_reg(&DEBUG_context) & STEP_FLAG)) EIP_reg(&DEBUG_context)--;
@@ -291,20 +329,98 @@
 
     if ((bpnum != 0) && (bpnum != -1))
     {
+        if( breakpoints[bpnum].condition != NULL )
+	  {
+	    cond_addr = DEBUG_EvalExpr(breakpoints[bpnum].condition);
+	    if( cond_addr.type == NULL )
+	      {
+		/*
+		 * Something wrong - unable to evaluate this expression.
+		 */
+		fprintf(stderr, "Unable to evaluate expression ");
+ 		DEBUG_DisplayExpr(breakpoints[bpnum].condition);
+		fprintf(stderr, "\nTurning off condition\n");
+		DEBUG_AddBPCondition(bpnum, NULL);
+	      }
+	    else if( ! DEBUG_GetExprValue( &cond_addr, NULL) )
+	      {
+		return TRUE;
+	      }
+	  }
+
+        if( breakpoints[bpnum].skipcount > 0 )
+	  {
+	    breakpoints[bpnum].skipcount--;
+	    if( breakpoints[bpnum].skipcount > 0 )
+	      {
+		return TRUE;
+	      }
+	  }
         fprintf( stderr, "Stopped on breakpoint %d at ", bpnum );
         DEBUG_PrintAddress( &breakpoints[bpnum].addr,
                             breakpoints[bpnum].addrlen, TRUE );
         fprintf( stderr, "\n" );
+	
+	/*
+	 * See if there is a source file for this bp.  If so,
+	 * then dig it out and display one line.
+	 */
+	DEBUG_FindNearestSymbol( &addr, TRUE, NULL, 0, &list);
+	if( list.sourcefile != NULL )
+	  {
+	    DEBUG_List(&list, NULL, 0);
+	  }
         return FALSE;
     }
 
+    /*
+     * If our mode indicates that we are stepping line numbers,
+     * get the current function, and figure out if we are exactly
+     * on a line number or not.
+     */
+    if( mode == EXEC_STEP_OVER 
+	|| mode == EXEC_STEP_INSTR )
+      {
+	if( DEBUG_CheckLinenoStatus(&addr) == AT_LINENUMBER )
+	  {
+	    (*count)--;
+	  }
+      }
+    else if( mode == EXEC_STEPI_OVER 
+	|| mode == EXEC_STEPI_INSTR )
+
+      {
+	(*count)--;
+      }
+
+    if( *count > 0 || mode == EXEC_FINISH )
+      {
+	/*
+	 * We still need to execute more instructions.
+	 */
+	return TRUE;
+      }
+    
+    /*
+     * If we are about to stop, then print out the source line if we
+     * have it.
+     */
+    if( (mode != EXEC_CONT && mode != EXEC_FINISH) )
+      {
+	DEBUG_FindNearestSymbol( &addr, TRUE, NULL, 0, &list);
+	if( list.sourcefile != NULL )
+	  {
+	    DEBUG_List(&list, NULL, 0);
+	  }
+      }
+
     /* If there's no breakpoint and we are not single-stepping, then we     */
     /* must have encountered an int3 in the Windows program; let's skip it. */
     if ((bpnum == -1) && !(EFL_reg(&DEBUG_context) & STEP_FLAG))
         EIP_reg(&DEBUG_context)++;
 
       /* no breakpoint, continue if in continuous mode */
-    return (mode == EXEC_CONT);
+    return (mode == EXEC_CONT || mode == EXEC_FINISH);
 }
 
 
@@ -314,16 +430,102 @@
  * Set the breakpoints to the correct state to restart execution
  * in the given mode.
  */
-void DEBUG_RestartExecution( enum exec_mode mode, int instr_len )
+enum exec_mode DEBUG_RestartExecution( enum exec_mode mode, int count )
 {
     DBG_ADDR addr;
+    DBG_ADDR addr2;
+    int bp;
+    int	delta;
+    int status;
+    unsigned int * value;
+    enum exec_mode ret_mode;
+    BYTE *instr;
 
     addr.seg = (CS_reg(&DEBUG_context) == WINE_CODE_SELECTOR) ?
                 0 : CS_reg(&DEBUG_context);
     addr.off = EIP_reg(&DEBUG_context);
 
-    if (DEBUG_FindBreakpoint( &addr ) != -1)
-        mode = EXEC_STEP_INSTR;  /* If there's a breakpoint, skip it */
+    /*
+     * This is the mode we will be running in after we finish.  We would like
+     * to be able to modify this in certain cases.
+     */
+    ret_mode = mode;
+
+    bp = DEBUG_FindBreakpoint( &addr ); 
+    if ( bp != -1 && bp != 0)
+      {
+	/*
+	 * If we have set a new value, then save it in the BP number.
+	 */
+	if( count != 0 && mode == EXEC_CONT )
+	  {
+	    breakpoints[bp].skipcount = count;
+	  }
+        mode = EXEC_STEPI_INSTR;  /* If there's a breakpoint, skip it */
+      }
+    else
+      {
+	if( mode == EXEC_CONT && count > 1 )
+	  {
+	    fprintf(stderr,"Not stopped at any breakpoint; argument ignored.\n");
+	  }
+      }
+    
+    if( mode == EXEC_FINISH && DEBUG_IsFctReturn() )
+      {
+	mode = ret_mode = EXEC_STEPI_INSTR;
+      }
+
+    instr = (BYTE *)PTR_SEG_OFF_TO_LIN( CS_reg(&DEBUG_context),
+					EIP_reg(&DEBUG_context) );
+    /*
+     * See if the function we are stepping into has debug info
+     * and line numbers.  If not, then we step over it instead.
+     * FIXME - we need to check for things like thunks or trampolines,
+     * as the actual function may in fact have debug info.
+     */
+    if( *instr == 0xe8 )
+      {
+	delta = *(unsigned int*) (instr + 1);
+	addr2 = addr;
+	DEBUG_Disasm(&addr2, FALSE);
+	addr2.off += delta;
+	
+	status = DEBUG_CheckLinenoStatus(&addr2);
+	/*
+	 * Anytime we have a trampoline, step over it.
+	 */
+	if( ((mode == EXEC_STEP_OVER) || (mode == EXEC_STEPI_OVER))
+	    && status == FUNC_IS_TRAMPOLINE )
+	  {
+#if 0
+	    fprintf(stderr, "Not stepping into trampoline at %x (no lines)\n",
+		    addr2.off);
+#endif
+	    mode = EXEC_STEP_OVER_TRAMPOLINE;
+	  }
+	
+	if( mode == EXEC_STEP_INSTR && status == FUNC_HAS_NO_LINES )
+	  {
+#if 0
+	    fprintf(stderr, "Not stepping into function at %x (no lines)\n",
+		    addr2.off);
+#endif
+	    mode = EXEC_STEP_OVER;
+	  }
+      }
+
+
+    if( mode == EXEC_STEP_INSTR )
+      {
+	if( DEBUG_CheckLinenoStatus(&addr) == FUNC_HAS_NO_LINES )
+	  {
+	    fprintf(stderr, "Single stepping until exit from function, \n");
+	    fprintf(stderr, "which has no line number information.\n");
+	    
+	    ret_mode = mode = EXEC_FINISH;
+	  }
+      }
 
     switch(mode)
     {
@@ -332,14 +534,35 @@
         DEBUG_SetBreakpoints( TRUE );
         break;
 
+    case EXEC_STEP_OVER_TRAMPOLINE:
+      /*
+       * This is the means by which we step over our conversion stubs
+       * in callfrom*.s and callto*.s.  We dig the appropriate address
+       * off the stack, and we set the breakpoint there instead of the
+       * address just after the call.
+       */
+      value = (unsigned int *) ESP_reg(&DEBUG_context) + 2;
+      addr.off = *value;
+      EFL_reg(&DEBUG_context) &= ~STEP_FLAG;
+      breakpoints[0].addr    = addr;
+      breakpoints[0].enabled = TRUE;
+      breakpoints[0].in_use  = TRUE;
+      breakpoints[0].skipcount = 0;
+      breakpoints[0].opcode  = *(BYTE *)DBG_ADDR_TO_LIN( &addr );
+      DEBUG_SetBreakpoints( TRUE );
+      break;
+
+    case EXEC_FINISH:
+    case EXEC_STEPI_OVER:  /* Stepping over a call */
     case EXEC_STEP_OVER:  /* Stepping over a call */
         if (DEBUG_IsStepOverInstr())
         {
             EFL_reg(&DEBUG_context) &= ~STEP_FLAG;
-            addr.off += instr_len;
+            DEBUG_Disasm(&addr, FALSE);
             breakpoints[0].addr    = addr;
             breakpoints[0].enabled = TRUE;
             breakpoints[0].in_use  = TRUE;
+	    breakpoints[0].skipcount = 0;
             breakpoints[0].opcode  = *(BYTE *)DBG_ADDR_TO_LIN( &addr );
             DEBUG_SetBreakpoints( TRUE );
             break;
@@ -347,7 +570,32 @@
         /* else fall through to single-stepping */
 
     case EXEC_STEP_INSTR: /* Single-stepping an instruction */
+    case EXEC_STEPI_INSTR: /* Single-stepping an instruction */
         EFL_reg(&DEBUG_context) |= STEP_FLAG;
         break;
     }
+    return ret_mode;
+}
+
+int
+DEBUG_AddBPCondition(int num, struct expr * exp)
+{
+    if ((num <= 0) || (num >= next_bp) || !breakpoints[num].in_use)
+    {
+        fprintf( stderr, "Invalid breakpoint number %d\n", num );
+        return FALSE;
+    }
+
+    if( breakpoints[num].condition != NULL )
+      {
+	DEBUG_FreeExpr(breakpoints[num].condition);
+	breakpoints[num].condition = NULL;
+      }
+
+    if( exp != NULL )
+      {
+	breakpoints[num].condition = DEBUG_CloneExpr(exp);
+      }
+
+   return TRUE;
 }