/****************************************************************************
**
**  Name:  memCmp.c
**
**  Description:
**     This is the memory compare command code for the Thunderbird
**     memory server.
**
**
**
**  $Log:   S:/tbird/mt2_186/mem/memcmp.c_v  $
** 
**    Rev 1.1   13 Jan 1997 10:30:36   Judy
** fixed for popup message error
** 
**    Rev 1.0   16 Dec 1996 13:50:24   Judy
** Initial revision.
** 
** 
**    Rev 1.0   24 Mar 1995 13:54:08   kevin
** Initial revision.
**  $Header:   S:/tbird/mt2_186/mem/memcmp.c_v   1.1   13 Jan 1997 10:30:36   Judy  $
**
**
**  Copyright (C) 1995 Microtek International.  All rights reserved.
**
*****************************************************************************/

/*
 * -----------------------------------------
 *  General purpose section function index
 * -----------------------------------------
 *
 *  DestroyCopyAddrDescriptors(void)
 *  CreateCopyAddrDescriptors(void)
 *    alloc and dealloc descriptors for the user interface
 *    address objects.
 *
 *  SetAddressSpaceDefaults(void)
 *    set up any defaults that the parser/dialog may
 *    be expecting.
 *
 *
 * -------------------------------------
 *  parser section function index
 * -------------------------------------
 *
 *  IsCopyCmdKeyword( LPSTR str )
 *     test passed string againt tokens for the copy command
 *
 *  ParseCliCopyMemory(LPSTR cmdString, U32 argc, U32 argv[])
 *     Parse command line and convert results into address
 *     descriptors and other variables, the native form used by
 *     the MemCopy() call in memory.c   (this is just what the other
 *     CLI functions do, they just do it locally, with in line code).
 *
 *
 *   MemCliCopyMemory(LPSTR cmdString, U32 argc, U32 argv[])
 *     Local entry point from MemCli.c DLL entry point.
 *     Calls ParseCliCopyMemory, then MemCopy().
 *     This extra level is performed to let us keep
 *     the native form (descriptors, ie, the cpy_* variables)
 *     local to this module.
 *
 *
 *
 * -------------------------------------
 *  dialog section function index
 * -------------------------------------
 *  MemCpyXferToLocal(HWND hDlg)
 *  MemCpyUnloadControls(HWND hDlg)
 *  MemCpyLoadControlsFromLocal(HWND hDlg)
 *    manages a local copy of memory parameters, just in case the user
 *    wants to press cancel.
 *
 *
 *   BOOL EXPORT MemCpyDlg(HWND hDlg, .... . LONG lParam)
 *      the dialog proc
 *
 *
 *  See also:
 *    Dialog Template:  mcpydlg.dlg, mcpydlg.res
 *    Dialog Constants: mcpydlg.h
 *
 *    note:  IDD_CPY_... are dialog controls, per convention
 *
 *
 *
 */


                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/

#ifndef _ADDR_
#include "addr.h"
#endif

#ifndef _BASEWIND_
#include "basewind.h"
#endif

#ifndef _CLISRV_
#include "clisrv.h"
#endif

#ifndef _CLIULIB_
#include "cliulib.h"
#endif

#ifndef _HLPENTRY_
#include "hlpentry.h"
#endif

#ifndef _HEAP_
#include "heap.h"
#endif

#ifndef _MEMCLI_
#include "memcli.h"
#endif

#ifndef _MEMLOCAL_
#include "memlocal.h"
#endif

#ifndef _PROC_
#include "proc.h"
#endif

#ifndef _SDPROBE_
#include "sdprobe.h"
#endif

#ifndef _SSHARED_
#include "sshared.h"
#endif

#ifndef __STDLIB_H
#include "stdlib.h"
#endif

#ifndef __STDIO_H
#include "stdio.h"
#endif

#ifndef __STRING_H
#include "string.h"
#endif

#ifndef _TBIRDMEM_
#include "tbirdmem.h"
#endif


#ifndef _MCPYDLG_
#include "mcpydlg.h"      // this is the dialog box constants
#endif

#ifndef  _SDS2ABI_
#include "sds2abi.h"
#endif
                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/

// size of symbol fields in dialog boxes.
#define   ADDR_LENGTHS   60


// text for the keywords
#define TO_TEXT      "to"
#define LENGTH_TEXT  "length"
#define TARGET_TEXT "target"


                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/
// Handle of the DLL instance: saved by LibMain
extern HANDLE hLib;

// Handle to send to shell
extern HANDLE cliServerHandle;

                       /***************************
                        *                         *
                        *    PRIVATE VARIABLES    *
                        *                         *
                        ***************************/

// ---------------------------------------------------------
//    SHARED DATA "GLOBAL" TO FUNCTIONS IN THIS MODULE
// ---------------------------------------------------------
//  This is the native form of the memory copy command
//  the parser (ParseCliCopyMemory) and dialog both
//  place results here.
//
// used for symbol parsing and range calculations
// that use Address server (addr.dll)
PRIVATE DESCRIPTOR  cpySrcDesc    = NULL;   // passed to MemCmp()
PRIVATE DESCRIPTOR  cpyDestDesc   = NULL;
PRIVATE DESCRIPTOR  cpySrcEndDesc = NULL;   // used to parse symbols into length

// data as passed to firmware is NOT entirely in descriptors
// some components are passed instead.
PRIVATE BOOLEAN     cpySrcTarget;     // passed in SD_COPY_SRC_TARG
PRIVATE U32         cpyLength;        // passed in SD_COPY_LENGTH
PRIVATE BOOLEAN     cpyDestTarget;    // passed in SD_COPY_DES_TARG

PRIVATE BOOLEAN  lengthKeyword;
PRIVATE BOOLEAN  toKeyword;
PRIVATE BOOLEAN  srcSpaceKeyword;
PRIVATE BOOLEAN  dstSpaceKeyword;
PRIVATE BOOLEAN  srcTargetKeyword;
PRIVATE BOOLEAN  dstTargetKeyword;

PRIVATE ADDR_SPACE  srcAddrSpace;
PRIVATE ADDR_SPACE  dstAddrSpace;


//--------------------------------------------------------
//  Variables local to the dialog
//--------------------------------------------------------
// these are dialog-local copies (dlgLocal...) of params, to be
// thrown away if user presses cancel.
//   loaded from native form by MemCpyXferToLocal(..)
//
//--------------------------------------------------------
//

PRIVATE CHAR dlgLocalSrcStartAddr[ADDR_LENGTHS];
PRIVATE CHAR dlgLocalSrcEndAddr[ADDR_LENGTHS];
PRIVATE CHAR dlgLocalDestStartAddr[ADDR_LENGTHS];


// for the following group, the values defined by control IDs
// ie, "dlgLocalPartition_End_or_Length" is one of
//      (IDD_CPY_END_USES_ADDRESS or IDD_CPY_END_USES_LENGTH)
//  must be translated from real values
PRIVATE  BOOLEAN     dlgLocalSrcTarget;
PRIVATE  BOOLEAN     dlgLocalDestTarget;
PRIVATE  ADDR_SPACE  dlgLocalSrcSpace;
PRIVATE  ADDR_SPACE  dlgLocalDestSpace;

// controls dialog box mode
PRIVATE  WORD   dlgLocalPartitionEndOrLength = IDD_CPY_END_USES_ADDRESS;

// controls CreateCopyAddrDescriptors activity
PRIVATE  BOOLEAN  descriptorsCreated = FALSE;


                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/


RETCODE PRIVATE DestroyCopyAddrDescriptors(VOID);
RETCODE PRIVATE CreateCopyAddrDescriptors(VOID);
RETCODE PRIVATE SetAddressSpaceDefaults(VOID);
BOOLEAN PRIVATE KeywordCheck(LPSTR str);
VOID PRIVATE KeywordInit(VOID);

VOID    PRIVATE MemDisplayError(HWND hwnd, RETCODE errCode);
RETCODE PRIVATE MemCpyXferToLocal(VOID);
RETCODE PRIVATE MemCpyUnloadControls(HWND hDlg);
RETCODE PRIVATE MemCpyLoadControlsFromLocal(HWND hDlg);


BOOL EXPORT MemCmpDlgProc(HWND hDlg, WORD message, WORD wParam, LONG lParam);









                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/


/**************************************************************
**    DestroyCopyAddrDescriptors
**
**  note that addr library will accept NULL descriptor.
**    it just returns an error code...
**    return the first error that appears
**
** ************************************************************
*/

RETCODE PRIVATE DestroyCopyAddrDescriptors(VOID) {

   RETCODE err;
   RETCODE returnedErr = GOOD;

   // prefer memory leaks to access of uninitialized memory
   descriptorsCreated = FALSE;
   if (cpySrcDesc != NULL) {
      err = AdrDestroyAddress(cpySrcDesc);
      if(returnedErr==GOOD)
         returnedErr=err;
   }
   if (cpySrcEndDesc != NULL) {
      err = AdrDestroyAddress(cpySrcEndDesc);
      if(returnedErr==GOOD)
         returnedErr=err;
   }
   if (cpyDestDesc != NULL) {
      err = AdrDestroyAddress(cpyDestDesc);
      if(returnedErr==GOOD)
         returnedErr=err;
   }
   return returnedErr;
}


/**************************************************************
**  CreateCopyAddrDescriptors( )
**
** create address descriptors for the copy.
**  if any are not created, calls DestroyCopyAddrDescriptors()
**
**  we ignore any errors from DestroyCopyAddrDescriptors()...we
**  want to return original reason for the error.
**
***************************************************************
*/
RETCODE PRIVATE CreateCopyAddrDescriptors(VOID) {

   RETCODE err = GOOD;


   if(descriptorsCreated == TRUE)
      return GOOD;
   cpySrcDesc    = NULL;
   cpySrcEndDesc = NULL;
   cpyDestDesc   = NULL;

   err = AdrCreateAddress(&cpySrcDesc);
   if (err != GOOD)  {
      DestroyCopyAddrDescriptors();
      return err;
   }
   err = AdrCreateAddress(&cpySrcEndDesc);
   if (err != GOOD)  {
      DestroyCopyAddrDescriptors();
      return err;
   }
   err = AdrCreateAddress(&cpyDestDesc);
   if (err != GOOD)  {
      DestroyCopyAddrDescriptors();
      return err;
   }
   descriptorsCreated = TRUE;
   return GOOD;
}


/**************************************************************
**   SetAddressSpaceDefaults(  )
**
** set up any defaults that the parser/dialog may
** be expecting.  Currently this is:
**
**  space     = SPACE_DEFAULT;
** map mode  = FALSE (use map, not target)
**  (write into address descriptors)
**
**************************************************************
*/
RETCODE PRIVATE SetAddressSpaceDefaults(VOID) {

   RETCODE    err = GOOD;

   err = AdrSetAddrSpace(cpySrcDesc, SPACE_DEFAULT);
   if (err != GOOD)  {
      return err;
   }
   err = AdrSetAddrSpace(cpyDestDesc, SPACE_DEFAULT);
   if (err != GOOD)  {
      return err;
   }
   cpySrcTarget = FALSE;   // IDD_CPY_SRC_MAP
   cpyDestTarget = FALSE;  // IDD_CPY_To_Map;
   return GOOD;
}


/*************************************************************
** KeywordInit()
**
**************************************************************
**/
VOID KeywordInit(VOID) {

   toKeyword = FALSE;
   lengthKeyword = FALSE;
   srcTargetKeyword = FALSE;
   dstTargetKeyword = FALSE;
   srcSpaceKeyword = FALSE;
   dstSpaceKeyword = FALSE;
}


/**************************************************************
**   KeywordCheck( LPSTR string )
**
**   Test incoming token against the possible keywords.
**
**  NOTE:  use "strnicmp" rather than *NON* ANSI "strncmpi"
*****************************************************************
**/

BOOLEAN PRIVATE KeywordCheck(LPSTR str) {
   U8 paramLen = strlen(str);
   BOOLEAN found = TRUE;

   // keywords
   if (!toKeyword && strnicmp(str, TO_TEXT, paramLen)==0) {
      toKeyword = TRUE;
   }
   else if (!lengthKeyword && strnicmp(str, LENGTH_TEXT, paramLen)==0) {
      lengthKeyword = TRUE;
   }
   else if (!toKeyword && !srcTargetKeyword && 
         strnicmp(str, TARGET_TEXT, paramLen)==0) {
      srcTargetKeyword = TRUE;
   }
   else if (toKeyword && !dstTargetKeyword &&
         strnicmp(str, TARGET_TEXT, paramLen)==0) {
      dstTargetKeyword = TRUE;
   }
   else if (!toKeyword && !srcSpaceKeyword &&
         AdrTranslateSpace(str,&srcAddrSpace)==0) {
      srcSpaceKeyword = TRUE;
   }
   else if (toKeyword && !dstSpaceKeyword &&
         AdrTranslateSpace(str,&dstAddrSpace)==0) {
      dstSpaceKeyword = TRUE;
   }
   else 
      found = FALSE;
   return (found);
}


/*******************************************************
**
**  MemDisplayError(HWND hwnd, RETCODE err)
**
**  Displays and error message box using message server.
**
**  there is a BUG in ErrDisplayErrorEx...no window handle!!!
**    (will replace it)
**  called  ErrDisplayErrorExOwned(HWND hwnd.....)
**
** if hWnd == NULL, it means we were called from CLI
**
**
**  note that NULL passed in hDlg will have it call Ex.
**  this means DLG vs CLI calls differ.
************************************************************
*/
#pragma argsused
VOID PRIVATE MemDisplayError(HWND hwnd, RETCODE errCode)
{
   S16  buttonID;

// for now, just call "Ex"
// future functon will call ExOwned() that takes a window handle
   ErrDisplayErrorEx( errCode, FORCE_POPUP,
               MB_TYPE_OK, (S16 FAR *)&buttonID );

}


// ------------------------------------------------------
//   Memory Copy dialog and its support procedures
// ------------------------------------------------------

/***********************************************************
**
**  MemCpyXferToLocal(VOID)
**
**
** copy native form into local data area
** error conditions from address server errors
**
** Called from:   INITDIALOG mesaage in dialog proc
** inputs:
**    cpySrcDesc
**    cpyDestDesc
**    cpyLength
** outputs:
** returns:    address server errors
**
**/
#pragma argsused
RETCODE PRIVATE MemCpyXferToLocal(VOID)
{
   RETCODE err;

   err = AdrConvAddressToTextWithParams(cpySrcDesc,
                                         TRUE, FALSE,
                                         dlgLocalSrcStartAddr);
   if(err!=GOOD)
      return err;
   // set display mode from previous usage
   if(dlgLocalPartitionEndOrLength == IDD_CPY_END_USES_LENGTH)  {
      wsprintf(dlgLocalSrcEndAddr, "0x%lX", cpyLength);
   } else {
      err = AdrConvAddressToTextWithParams(cpySrcEndDesc,
                                         TRUE, FALSE,
                                         dlgLocalSrcEndAddr);
      if(err!=GOOD)
         return err;
      // force other mode
      dlgLocalPartitionEndOrLength = IDD_CPY_END_USES_ADDRESS;
   }
   // destination
   err = AdrConvAddressToTextWithParams(cpyDestDesc,
                                         TRUE, FALSE,
                                        dlgLocalDestStartAddr);
   if(err!=GOOD)
      return err;
   // the address space is fixed when in dialog
   dlgLocalSrcSpace  = SPACE_DEFAULT;
   dlgLocalDestSpace = SPACE_DEFAULT;
   // set the target/map from the current definition
   dlgLocalSrcTarget  =  cpySrcTarget;
   dlgLocalDestTarget =  cpyDestTarget;

   return GOOD;
}


/***********************************************************
**
**  MemCpyUnloadControls(HWND hDlg)
**
**
** Fetch contents of dialog box controls and convert to
** native form.
**
** Called from:   IDOK mesaage in dialog proc
** inputs:  hDlg  dialog window handle
**
** global variables changed:
**    cpySrcDesc
**    cpyDestDesc
**    cpyLength
**  if successful all are changed.
**
**  if "not successful" only SOME are changed.
**  This is a syntax error.  We simply return the error code.
**  The error is then displayed by a call to the errortext
**  server from within the dialog procedure and the "exit dialog"
**  is NOT permitted.
**
*/

RETCODE PRIVATE MemCpyUnloadControls(HWND hDlg) {

   RETCODE    err;
   LPSTR      endptr;         // used by strtoul

   GetDlgItemText(hDlg,IDD_CPY_SRC_START, dlgLocalSrcStartAddr, ADDR_LENGTHS);
   GetDlgItemText(hDlg,IDD_CPY_SRC_END,   dlgLocalSrcEndAddr,   ADDR_LENGTHS);
   GetDlgItemText(hDlg,IDD_CPY_DEST_START,dlgLocalDestStartAddr,ADDR_LENGTHS);
   err = AdrConvTextToAddress(cpySrcDesc, dlgLocalSrcStartAddr );
   if(err!=GOOD)
      return GOOD;
   // save as length ONLY.
   // dlgLocalSrcEndAddr contains a length field
   // if mode is absolute, convert absolute to length
   if(dlgLocalPartitionEndOrLength == IDD_CPY_END_USES_ADDRESS ) {
      err = AdrConvTextToAddress(cpySrcEndDesc,
                                  dlgLocalSrcEndAddr );
      if(err!=GOOD)
         return err;
      // calculate difference to get length
      // extract difference between two addresses
      err = AdrRangeOfAddresses( cpySrcDesc, cpySrcEndDesc, &cpyLength);
      if(err!=GOOD)
         return err;
   } else {
      // process length (a number ONLY, no symbols)
      // allow format to determine base
      cpyLength = strtoul( dlgLocalSrcEndAddr ,&endptr, 0);
      if(err!=GOOD)
         return GOOD;
      dlgLocalPartitionEndOrLength = IDD_CPY_END_USES_LENGTH;
   }
   // destination
   err = AdrConvTextToAddress(cpyDestDesc,
                                  dlgLocalDestStartAddr );
   if(err!=GOOD)
      return GOOD;
   err = AdrSetAddrSpace(cpySrcDesc, SPACE_DEFAULT);
   if(err!=GOOD)
      return err;
   err = AdrSetAddrSpace(cpyDestDesc, SPACE_DEFAULT);
   if(err!=GOOD)
      return err;
   // get the target/map (holds TRUE/FALSE)
   cpySrcTarget  = dlgLocalSrcTarget;
   cpyDestTarget = dlgLocalDestTarget;
   return GOOD;
}


/***********************************************************
**
**  MemCpyLoadControlsFromLocal(HWND hDlg)
**
**
** Store contents of local variables into the dialog box
** controls.
**
** Called from:   INITDIALOG mesaage in dialog proc
** inputs:  hDlg  window handle
**
** inputs from global variables:
**  dlgLocalSrcStartAddr[ADDR_LENGTHS];
**  dlgLocalSrcEndAddr[ADDR_LENGTHS];
**  dlgLocalDestStartAddr[ADDR_LENGTHS];
**  dlgLocalSrcTarget;
**  gLocalDestTarget;
**  dlgLocalSrcSpace;
**  dlgLocalDestSpace;
**  dlgLocalPartitionEndOrLength;
**
**
*/

RETCODE PRIVATE MemCpyLoadControlsFromLocal(HWND hDlg) {

   RETCODE err;
   PROC_SYSTEM_TYPE  systemType;

   // transfer to controls
   SetDlgItemText (hDlg, IDD_CPY_SRC_START,   dlgLocalSrcStartAddr );
   SetDlgItemText (hDlg, IDD_CPY_SRC_END,     dlgLocalSrcEndAddr );
   SetDlgItemText (hDlg, IDD_CPY_DEST_START,  dlgLocalDestStartAddr );
   // set end/length radio and title text
   CheckRadioButton (hDlg, IDD_CPY_END_USES_ADDRESS,
                           IDD_CPY_END_USES_LENGTH,
                           dlgLocalPartitionEndOrLength );
   // set MAP and TARGET radio buttons
   //  note:  dlgLocalSrcTarget is set FALSE ("redundantly")
   //  on PURPOSE.  It may not be redundant.
   //  (it depends on TRUE/FALSE implementation)
   //  If it is not TRUE it does not mean that it is FALSE!
   //  Instead, it may be indeterminate.
   //  Other code, somewhere else, may check for FALSE, and
   //  found the indeterminate value instead. (zap! Ouch!)
   err = ProcReturnSystemType( &systemType );
   if(err!=GOOD)
      return err;
   if(systemType == PROC_POWERPACK || systemType == PROC_MICEPACK) {
      if(dlgLocalSrcTarget==TRUE) {
         CheckRadioButton (hDlg, IDD_CPY_SRC_MAP,
                           IDD_CPY_SRC_TARGET,
                           IDD_CPY_SRC_TARGET );
      }
      else {
         CheckRadioButton (hDlg, IDD_CPY_SRC_MAP,
                                 IDD_CPY_SRC_TARGET,
                                 IDD_CPY_SRC_MAP );
         dlgLocalSrcTarget = FALSE;
      }
      if(dlgLocalDestTarget==TRUE) {
         CheckRadioButton (hDlg, IDD_CPY_DEST_MAP,
                               IDD_CPY_DEST_TARGET,
                               IDD_CPY_DEST_TARGET );
      }
      else {
         CheckRadioButton (hDlg, IDD_CPY_DEST_MAP,
                                 IDD_CPY_DEST_TARGET,
                                 IDD_CPY_DEST_MAP );
         dlgLocalDestTarget = FALSE;
      }
   } // end powerpack
   else {
       EnableWindow(GetDlgItem(hDlg, IDD_CPY_SRC_MAP)    , FALSE);
       EnableWindow(GetDlgItem(hDlg, IDD_CPY_SRC_TARGET) , FALSE);
       EnableWindow(GetDlgItem(hDlg, IDD_CPY_DEST_MAP)   , FALSE);
       EnableWindow(GetDlgItem(hDlg, IDD_CPY_DEST_TARGET), FALSE);

   }
   // set focus to somewhere safe (mainly done for EnableWindow() calls
   // above, but I do not like special cases).  In NO case can focus
   // be left on the radio button that has just been disabled.  Keyboard
   // operations in the dialog will be halted...can't exit via abort either.
   // Focus would normally be set (by Windows) to this control anyway,
   // as specified by the dialog template.
   SetFocus( GetDlgItem(hDlg, IDD_CPY_SRC_START) );
   return GOOD;
}

/******************************************************
**
**   MemCpyDlgProc
**
** The dialog window procedure
**
**  returns result to DialogBox callerwith EndDialog() function::
**    TRUE:   user pressed OK
**    FALSE:  user pressed cancel
**
**  After pressing OK, if parse is not successful (or
**  some other error occurs), we display the error, and
**  permit a retry.  User can exit with Cancel, though.
**
**  Note that errors are NOT propagated up to Actor level.
**
**
**  The params follow Windows 3.0 conventions, NOT those of Win3.1
**
**  Return value is standard also: a Windows BOOL, NOT the
**  Powerviews BOOLEAN!
**  returns TRUE of message was handled, FALSE if not handled.
**
******************************************************
*/
#pragma argsused
BOOL EXPORT MemCmpDlgProc(HWND hDlg, WORD message, WORD wParam, LONG lParam) {

   RETCODE  err;

   switch (message)
   {
      case WM_INITDIALOG:

      // some items are not saved between invocations
      err = SetAddressSpaceDefaults();
      RegisterHelpEntry(HI_MESSAGEBOXEX, hDlg, 6032);
      if(err!=GOOD) {
          MemDisplayError(hDlg, err);
          return TRUE;
      }
      err = MemCpyXferToLocal();     // load local copies of params
      if(err!=GOOD)  {
         MemDisplayError(hDlg, err);
         return TRUE;
      }
      MemCpyLoadControlsFromLocal(hDlg);
      return TRUE;

      case WM_COMMAND:

      switch(wParam) {
          case IDOK:
             err = MemCpyUnloadControls(hDlg);
             if(err!=GOOD)  {
                MemDisplayError(hDlg, err);   // parse error
                return TRUE;
             }
             EndDialog(hDlg, TRUE);
             return TRUE;

          case IDHELP:
              WinHelp(hDlg, "PWRVIEWS.HLP",
                 HELP_CONTEXT, 6032);
              return FALSE;
  
          case IDCANCEL:
              EndDialog(hDlg, FALSE);
              return TRUE;

          case IDD_CPY_END_USES_ADDRESS:
          case IDD_CPY_END_USES_LENGTH:
              dlgLocalPartitionEndOrLength = wParam;
              CheckRadioButton (hDlg, IDD_CPY_END_USES_ADDRESS,
                                      IDD_CPY_END_USES_LENGTH,
                                      wParam );
              return TRUE;


          // MAP or TARGET control
          case IDD_CPY_SRC_TARGET:
             dlgLocalSrcTarget = TRUE ;
             CheckRadioButton (hDlg, IDD_CPY_SRC_MAP,
                                  IDD_CPY_SRC_TARGET, wParam );
             EnableWindow(GetDlgItem(hDlg, IDD_CPY_DEST_START), FALSE);
             EnableWindow(GetDlgItem(hDlg, MEMCPY_ADDRTEXT)   , FALSE);
             dlgLocalDestTarget = FALSE ;
             return TRUE;

          case IDD_CPY_SRC_MAP:
             dlgLocalSrcTarget = FALSE ;
             CheckRadioButton (hDlg, IDD_CPY_SRC_MAP,
                                IDD_CPY_SRC_TARGET, wParam );
             EnableWindow(GetDlgItem(hDlg, IDD_CPY_DEST_START), TRUE);
             EnableWindow(GetDlgItem(hDlg, MEMCPY_ADDRTEXT)   , TRUE);
             dlgLocalDestTarget = FALSE ;
             return TRUE;

          case IDD_CPY_DEST_TARGET:
             dlgLocalDestTarget = TRUE ;
             CheckRadioButton (hDlg, IDD_CPY_DEST_MAP,
                                    IDD_CPY_DEST_TARGET, wParam );
             return TRUE;

          case IDD_CPY_DEST_MAP:
             dlgLocalDestTarget = FALSE ;
             CheckRadioButton (hDlg, IDD_CPY_DEST_MAP,
                                  IDD_CPY_DEST_TARGET, wParam );
             return TRUE;

      } // end switch (wparam)
   } // end switch (message)
   return (FALSE);   // Didn't process a message
}


/******************************************************
**
** MemDlgCompareMemory  
**
**   Execute the dialog
**
**  called from ACTOR memory presenter menu item...
**
*******************************************************
**/

RETCODE EXPORT MemDlgCompareMemory(HWND hwnd)   {

   int      dlgRet;    // "int" is return type of DialogBox()
   RETCODE  err;
   RETCODE  copyErr;
   HCURSOR  hSaveCursor, hHourGlass;
   U32      addr1, addr2;
   U16      data1, data2;
   BOOLEAN  result;
   CHAR     tmpStr[80];
   ACCESS_SIZE size;

   Sds2AbiGetAccessSize(&size);
   err = CreateCopyAddrDescriptors();
   if(err!=GOOD)
      return err;
   dlgRet = DialogBox(hLib,           // instance (for dlg template)
           "MCMP_DIALOG",
            hwnd,                     // parent handle
           (FARPROC) MemCmpDlgProc);  // within DLL, 
                                      // no proc instance address reqd
   // if user pressed OK, perform the copy
   // using the native (parsed) form.
   if(dlgRet==TRUE)  {
      hHourGlass = LoadCursor(NULL, IDC_WAIT);
      hSaveCursor = SetCursor(hHourGlass);
      if ((copyErr = MemCompare(cpySrcDesc, cpyDestDesc, cpyLength, &result,
                           &addr1, &addr2, &data1, &data2)) != GOOD) {
         SetCursor(hSaveCursor);
         return(copyErr);
      }
      SetCursor(hSaveCursor);
      if (result)
         MessageBox(hwnd, "No difference", "Compare Memory", 
                    MB_OK|MB_ICONEXCLAMATION);
      else {
         if (size == SIZE_BYTE)
            wsprintf(tmpStr, "Difference at (0x%05lxp)=0x%02x,(0x%05lxp)=0x%02x",
                  addr1, data1&0xff, addr2, data2&0xff);
         else
            wsprintf(tmpStr, "Difference at (0x%05lxp)=0x%04x,(0x%05lxp)=0x%04x",
                  addr1, data1, addr2, data2);
         MessageBox(hwnd, tmpStr, "Compare Memory", MB_OK|MB_ICONEXCLAMATION);
      }
   }
   else copyErr = GOOD;

   return copyErr;
}

/*****************************************************************
**
** MemCliCompareMemory
**  registered with CLI in the .RC file
**
** Description:
**    Cli interface to the compare memory
**
** Syntax: compare <from_start_address> <from_end_address | LENGTH <len>>
**         TO <to_address>
**
** Input:
**    cmdString
**    argc
**    argv
**
** Output: no parameters
**
**
**     DLL entry point from CLI.
**     Calls ParseCliCompareMemory, then MemComapre().
**
**
*****************************************************************************/
#pragma argsused
RETCODE EXPORT MemCliCompareMemory(LPSTR cmdString, U32 argc, U32 argv[]) {

   RETCODE  err;
   HCURSOR  hSaveCursor, hHourGlass;
   LPSTR      endptr;         // used by strtoul
   ADDR_COMPARE result;       // result of comparison
   LOOP_VAR   args;
   LOOP_VAR   addrFound=0;            
   BOOLEAN    lengthFound=FALSE;
   BOOLEAN    getAddress=TRUE;
   BOOLEAN    compareResult;
   U32 retAddr1, retAddr2;
   U16 retData1, retData2;
   U8  outputBuff[80];
   ACCESS_SIZE size;

   Sds2AbiGetAccessSize(&size);
   // check for minimum number of tokens (5)
   if (argc < 4)
      return ER_CLI_SYNTAX;
   if (argc > 6)
      return ER_CLI_SYNTAX;
   KeywordInit();
   // check for required keywords - TO
   for (args=1; args < argc; args++)
      KeywordCheck(&(cmdString[(U16)argv[args]]));
   if (!toKeyword)
      return ER_CLI_SYNTAX;
   if ((err = CreateCopyAddrDescriptors()) != GOOD)
      return err;
   KeywordInit();
   // Parse the command        
   for (args=1; args < argc; args++) {
      if (!KeywordCheck(&(cmdString[(U16)argv[args]]))) {
         DESCRIPTOR *addrDesc;
         getAddress = TRUE;
         if (addrFound == 0) {
            addrDesc = &cpySrcDesc;
            addrFound++;     
         }
         else if (!lengthFound && lengthKeyword) {
            lengthFound = TRUE;
            getAddress = FALSE;
            cpyLength = strtoul(&cmdString[(U16)argv[args]],&endptr,0);
            if (cpyLength <= 0)
               return ER_CLI_SYNTAX;
         }
         else if (!toKeyword && (addrFound == 1)) {
            addrFound++;
            addrDesc = &cpySrcEndDesc;
         }
         else {
            addrFound++;
            addrDesc = &cpyDestDesc;
         }
         if (getAddress) {
            if ((err = AdrConvTextToAddress(*addrDesc,
                  &cmdString[(U16)argv[args]])) != GOOD)
               return err;
         }
      }
   }
   if (!lengthFound) { 
      //  second source address specified
      // make sure first address < second address.
      err = AdrCompareAddresses(cpySrcDesc, cpySrcEndDesc, &result);
      if (result != SECOND_ADDR_GREATER)
          return ER_CLI_SYNTAX;
      // extract difference between two addresses for length
      if ((err = AdrRangeOfAddresses( cpySrcDesc, cpySrcEndDesc, 
            &cpyLength)) != GOOD)
         return err;
   }
   // check for destination address.
   if ((addrFound == 1) || ((addrFound == 2) && !lengthFound)) {
      // dst address not specified
         return ER_CLI_SYNTAX;
   }
   //  perform the compare.
   hHourGlass = LoadCursor(NULL, IDC_WAIT);
   hSaveCursor = SetCursor(hHourGlass);
   err = MemCompare(cpySrcDesc, cpyDestDesc, cpyLength, &compareResult, 
                    &retAddr1, &retAddr2, &retData1, &retData2);
   SetCursor(hSaveCursor);
   // do not destroy the descriptors they are reused by the dialog.
   if (compareResult) 
      SendCliMessage(cliServerHandle,(LPSTR)"Memory no difference.");
   else {
      if (size == SIZE_BYTE)
         sprintf(outputBuff,
            "Memory different at: (0x%05lxp)=0x%02x, (0x%05lxp)=0x%02x",
            retAddr1, retData1&0xff, retAddr2, retData2&0xff);
      else
         sprintf(outputBuff,
            "Memory different at: (0x%05lxp)=0x%04x, (0x%05lxp)=0x%04x",
            retAddr1, retData1, retAddr2, retData2);
      SendCliMessage(cliServerHandle,outputBuff);
   }
   return (GOOD);
}


/******************************** E O F ***********************************/
