macro_file MEUTIL2;

#include METOOLS.SH

#ifdef Windows
	#include WINDOWS.SH
	#include MEW_DLGS.SH
	#include DIALOG.SH
	#include MEUTIL2.SH
#endif

global {
	int g_BufferActive		"!Buffer_Active";
}
/*******************************************************************************
														MULTI-EDIT MACRO FILE

Name: MEUTIL2

UNDBLK						- Undent block macro.
INDBLK						- Indent block macro.
MARKBLCK					- Mark line block macro.
MCOLBLCK					- Mark columnar block macro.
MSTRBLCK					- Mark stream of text block macro.
BLOCKOFF					- Turn block mark off.
BLOCKOP						- Move, copy, and delete block operations.
SHOWCLIPBOARD			- Shows the  buffer(clipboard) in a window.
CUT								- Copies, Moves or Appends text into a hidden buffer.
PASTE							- Copies block from buffer into current file.
BLCKMATH					- Performs math operations on blocks of text.

								Copyright 1991 by American Cybernetics, Inc.
*******************************************************************************/

// Following Macros are used by the menu manager to check status of menu
// items
int CheckPersistent( ) {
	return (persistent_blocks != 0);
}

int CheckBlock( ) {
	return (block_stat == 0);
}

int CheckBuffer( ) {
	return ( !( g_BufferActive || Win3_Clipboard ) );
}

int CheckMarking( ) {
	return ( Marking != 0 );
}

int CheckNoMarking( ) {
	return ( Marking == 0 );
}

int CheckLineMarking( ) {
	return ( g_LastBlockType == 1 );
}

int CheckColMarking( ) {
	return ( g_LastBlockType == 2 );
}
int CheckStrMarking( ) {
	return ( ( g_LastBlockType == 3 ) || ( g_LastBlockType == 0 ) );
}

int CheckNIStrMarking( ) {
	return ( g_LastBlockType == 4 );
}

int UndBlk(
			int InBlk = Parse_Int( "/I=", MParm_Str ),
			int Message = Parse_Int( "/NM=", MParm_Str ) == 0,
			str Misc = MParm_Str
) trans2 {
/******************************************************************************
															 Multi-Edit Macro
															 15-Jul-93  15:43

  Function: Undents a marked block of text one tab stop.

  Entry   : int InBlk		 Will only undent when cursor is in block ( /I=1 )
 						int Message	 Show message ( /NM=1 no message )
						str Misc		 Optional parameters
							/NEM=1		  - Will not end block marking

  Exit    :	int
 							True 	= Block undented
							False	=	Block not undented

						 Copyright (C) 1989-95 by American Cybernectics, Inc.
********************************************************************( ldh )***/

	if ( InBlk == 0 ) {
		InBlk = g_ChkInBlock;
	}
  if ( InBlk == 1 ) {
    InBlk = CursorInBlock( True );			// Check cursor in block
	}
	else {
    InBlk = Block_Stat;                 // Block marked
	}
  if ( InBlk ) {

		int KeepMarking				= Parse_Int( "/NEM=", Misc );
		int	SavRefresh 				= Refresh;
  	int SavInsertMode 		= Insert_Mode;     // Save insert mode
		int SavPersistentBlks = Persistent_Blocks;
		int	BCol1 						= Block_Col1;
		int BCol2							= Block_Col2;
		int BLin2 						= Block_Line2;
		int	Col;

		if ( KeepMarking == 0 ) {
			KeepMarking = g_KeepBlkMarking;
		}
		Working;
		Refresh = False;          	 				// No screen update
    Insert_Mode = False;
		Persistent_Blocks = True;
		if ( KeepMarking < 1 ) {
			Block_End;
		}
		Push_Undo;
    Mark_Pos;
    Goto_Line( Block_Line1 );
    if ( Block_Stat == _ColBlock ) {     // Column block
      while ( C_Line <= BLin2 ) {
        Goto_Col( BCol1 );
        if ( Find_Text( "[^ \t\xFF]", 1, _RegExp ) && !At_Eol ) {
					Col = C_Col;
      		Tab_Left;
          if ( C_Col < BCol1 ) {
            Goto_Col( BCol1 );
					}
          Del_Chars( Col - C_Col );
				}
				Down;
			}
		}
		else {
			if ( ( Block_Stat == _StrBlock ) && ( BCol2 == 0 ) ) {
				--BLin2;
			}
      while ( C_Line <= BLin2 ) {
        First_Word;
        if ( !At_Eol ) {
					Col = C_Col;
        	Tab_Left;
          Del_Chars( Col - C_Col );
				}
        Down;
			}
		}
    if ( Message ) {
      Make_Message( "Block undented" );
		}
    Goto_Mark;
    Pop_Undo;
		Persistent_Blocks = SavPersistentBlks;
    Insert_Mode = SavInsertMode;
    Refresh = SavRefresh;
    Redraw;
	}
  return ( InBlk );

}  // UndBlk

int IndBlk(
			int InBlk = Parse_Int( "/I=", MParm_Str ),
			int Message = Parse_Int( "/NM=", MParm_Str ) == 0,
			str Misc = MParm_Str
) trans2 {
/******************************************************************************
                               Multi-Edit Macro
                               30-Aug-95  01:43

  Function: Indents a marked block of text one tab stop.

  Entry   : int InBlk		 Will only indent when cursor is in block ( /I=1 )
 						int Message	 Show message ( /NM=1 no message )
						str Misc		 Optional parameters
							/NEM=1		  - Will not end block marking

  Exit    :	int
 							True 	= Block indented
							False	=	Block not indented

						 Copyright (C) 1991-95 by American Cybernectics, Inc.
**********************************************************************(ldh)***/

	if ( InBlk == 0 ) {
		InBlk = g_ChkInBlock;
	}
  if ( InBlk == 1 ) {
    InBlk = CursorInBlock( True );			// Check cursor in block
	}
	else {
    InBlk = Block_Stat;                 // Block marked
	}
  if ( InBlk ) {

		int KeepMarking				= Parse_Int( "/NEM=", Misc );
    int SavRefresh 		 		= Refresh;
    int SavInsertMode 		= Insert_Mode;     // Save insert mode
		int SavPersistentBlks = Persistent_Blocks;
    int BCol1 			 	 		= Block_Col1;
		int BCol2							= Block_Col2;
    int BLin2 			 	 		= Block_Line2;
    int Col;

		if ( KeepMarking == 0 ) {
			KeepMarking = g_KeepBlkMarking;
		}
    Working;
    Refresh = False;                    // No screen update
    Insert_Mode = True;
		Persistent_Blocks = True;
		if ( KeepMarking < 1 ) {
			Block_End;
		}
    Push_Undo;
    Mark_Pos;
    Goto_Line( Block_Line1 );
    if ( Block_Stat == _ColBlock ) {     // Column block
      while ( C_Line <= BLin2 ) {
        Goto_Col( BCol1 );
        Tab_Right;
        Down;
			}
		}
		else {
			if ( ( Block_Stat == _StrBlock ) && ( BCol2 == 0 ) ) {
				--BLin2;
			}
      while ( C_Line <= BLin2 ) {
        First_Word;
        if ( !At_Eol ) {
          Tab_Right;
        }
        Down;
			}
		}
    if ( Message ) {
      Make_Message( "Block indented" );
		}
    Goto_Mark;
    Pop_Undo;
		Persistent_Blocks = SavPersistentBlks;
    Insert_Mode = SavInsertMode;
    Refresh = SavRefresh;
    Redraw;
	}
  return ( InBlk );

}  // IndBlk

macro MarkBlck trans2 {
/******************************************************************************
																MULTI-EDIT MACRO

Name:	MarkBlck

Description:	Starts and stops line oriented block marking.

Parameters:  /O=1	Does not turn block off if existing block is not a
 									line oriented block.

							(C) Copyright 1991-95 by American Cybernetics, Inc.
******************************************************************************/

  Rm( "MarkBlock /T=1" + MParm_Str );

}  // MarkBlck

macro MColBlck trans2 {
/******************************************************************************
																MULTI-EDIT MACRO

Name:	MColBlck

Description:	Starts and stops column oriented block marking.

Parameters:  /O=1	Does not turn block off if existing block is not a
 									column oriented block.

							(C) Copyright 1991-95 by American Cybernetics, Inc.
******************************************************************************/

  Rm( "MarkBlock /T=2" + MParm_Str );

}  // MColBlck

macro MStrBlck trans2 {
/******************************************************************************
																MULTI-EDIT MACRO

Name:	MStrBlck

Description:	Starts and stops stream oriented block marking.

Parameters:  /O=1	Does not turn block off if existing block is not a
 									stream oriented block.

							(C) Copyright 1991-95 by American Cybernetics, Inc.
******************************************************************************/

	Rm( "MarkBlock /T=" + Str( 4 - Stream_Block_Mode ) + MParm_Str );

}  // MStrBlck

macro BlockOff trans2 {
/******************************************************************************
																MULTI-EDIT MACRO

Name:	BLOCKOFF

Description:	Turns the current block marking off.

							(C) Copyright 1991-95 by American Cybernetics, Inc.
******************************************************************************/

	Rm( "MarkBlock /T=0" + MParm_Str );

}  // BlockOff

macro BLOCKOP TRANS2 {
/*******************************************************************************
																MULTI-EDIT MACRO

Name:	BLOCKOP

Description:	Does a block copy or move and then, if hard_cr is being used,
							does a reformat on the area under the block.

Parameters:		/BT=nn		nn is the operation type.
												0 = Block copy
												1 = Block Move
												2 = Block Delete
												3 = Inter-Window Copy
												4 = Inter-Window Move
												5 = Toggle persistent blocks

							 (C) Copyright 1991 by American Cybernetics, Inc.
*******************************************************************************/

	int  old_refresh, bt, bl, tb ;

	bt = parse_int( '/BT=', mparm_str );
	tb = block_stat;

	bl = block_line1;

	if( bt == 5 ) {
		persistent_blocks = (persistent_blocks == 0);
		goto exit;
	}
	if(  bt == 3  ) {
		RM( 'WINDOW^COPYBL' );
		tb = block_stat;
	}
	if(  bt == 4  ) {
		RM( 'WINDOW^MOVEBL' );
		tb = block_stat;
	}

	if(  block_stat == 0  ) {
		make_message('No block marked.');
		goto exit;
	}

	if(  bt == 0  ) {
		Copy_Block;
		Make_Message('Block copied.');
	}
	if(  bt == 1  ) {
		Move_Block;
		Make_Message('Block moved.');
	}
	if(  bt == 2  ) {
		Delete_Block;
		Make_Message('Block deleted.');
	}


	Old_refresh = refresh;
	Refresh = false;
	if(  (tb != 0) & (Hard_Cr != '|0') & (Hard_Cr != '')  ) {
		Mark_Pos;
		PUSH_UNDO;
		goto_line( bl );
		while(  C_Line <= Block_Line2  ) {
			RM( 'TEXT^REFORMAT /NR' );
		}

		Goto_Mark;
		POP_UNDO;
	}
exit:
	refresh = old_refresh;
}

#define _BUFFER_NAME FExpand(getuserpath( ) + 'BUFFER.' + Str(Buf_Num))

void SwitchToBuffer( int Buf_Num ) trans2 {
	str buf_name = _BUFFER_NAME;
	if ( switch_file_ex( buf_name, 1 ) == 0 )
	{
		switch_window(window_count);
		create_window;
		if(  error_level != 0  )
			return();
		window_attr = $81;
		file_name = buf_name;
	}
}

int ClipEventProc( int M ) {
/****************** Multi-Edit INTEGER Macro Function ***********************

 NAME:         ClipEventProc()

 DESCRIPTION:  Event processor for the buffer/clipboard window
							 Called only by the ME kernel.

 PARAMETERS:   None

 RETURNS:      0

*****************************07-08-93 02:00pm*******************************/

	int  t_persistent_blocks = persistent_blocks;
	int  tw = window_id;
	int l1 = wcmd_last_lparam;

	persistent_blocks = TRUE;
	switch ( m & 0xffff )
	{
		case EVENT_KEY_ENHANCED :
				pass_event_through;
				break;

		case EVENT_CURSOR_LINE :
		case EVENT_CURSOR_COL :
				break;

				#IFDEF windows
		case EVENT_WCMD :
				Wcmd_Execute( cur_window, m >> 16, l1 );
         if ( !(m >> 16 == global_int('~CLOSE_WCMD_ID')) )
        {
          break;
        }
				#ENDIF

    case EVENT_DELETE_WIN :
        set_global_int('!CLIP_SHOW', 0);
        set_global_int("!BUFFER_ACTIVE", 0 );
        set_global_int('!CLIP_LINK_WIN', 0);
        break;
	}
	persistent_blocks = t_persistent_blocks;
	if(window_id == tw)
	{
		window_name = 'BUFFER';
		file_changed = false;
	}
	else
	{
		int tr = refresh,
				tw2 = cur_window;

		refresh = false;
		if( switch_win_id( tw ))
		{
			switch_window(tw2);
		}
		else
		{
      set_global_int('!CLIP_OLD_WIN', 0);
      set_global_int('!CLIP_SHOW', 0 );
			set_global_int("!BUFFER_ACTIVE", 0 );
		}
		refresh = tr;
	}

	return(0);

}

void ShowClipboard( int buf_num = parse_int('/B=', mparm_str)) {
/******************** Multi-Edit VOID Macro Function ************************

 NAME:         ShowClipboard

 DESCRIPTION:  Display clipboard in a window

 PARAMETERS:   buf_name is the buffer number to display

*****************************07-08-93 02:01pm*******************************/

  int twin = window_id,
      orgbuffwin;

	if ( buf_num > 999 )
		buf_num = 999;
	if(  buf_num < 0  )
		buf_num = 0;
	if( !switch_file_ex( _BUFFER_NAME, 1 ) )
	{
		if( Win3_Clipboard )
		{
			SwitchToBuffer( buf_num );
			Win3_Paste;
		}
	}

  if ( (switch_file_ex(_BUFFER_NAME, 1)) && (!global_int('!CLIP_LINK_WIN')) )
  {
    orgbuffwin = cur_window;
    create_window;
    link_window(orgbuffwin);
    set_global_int('!CLIP_LINK_WIN', window_id);
  }

  if(switch_win_id(global_int('!CLIP_LINK_WIN')))
	{
		if(window_id != twin)
		{
			set_global_int('!CLIP_SHOW', 1 );
			set_global_int('!CLIP_OLD_WIN', twin );
			event_macro  = 'ClipEventProc';
			event_mode = EVENT_MODE_ENHANCED | EVENT_CURSOR_LINE | EVENT_CURSOR_COL |
                    EVENT_WCMD | EVENT_KEY_ENHANCED | EVENT_DELETE_WIN;
			window_name = 'BUFFER';
			Make_Window_Visible (1);
			redraw;
		}
		else
		{
			event_macro  = '';
			event_mode = 0;
      delete_window;
			switch_win_id(global_int('!CLIP_OLD_WIN'));
			rm("FINDWIN");
      set_global_int('!CLIP_LINK_WIN', 0);
			set_global_int('!CLIP_OLD_WIN', 0 );
			set_global_int('!CLIP_SHOW', 0 );
		}

	}
}

void Cut(
			int Buf_Num = Parse_Int( "/B=", MParm_Str ),
			str Flags		= MParm_Str
) trans2 {
/******************************************************************************
                               Multi-Edit macro
                               13-Jul-93  14:19

  Function: Copies, Moves and/or Appends text to a hidden buffer.
  Entry   : int Buf_Num		The buffer # (0 is the default) ( /B=# )
						str Flags			The operation flags
							/M    			- Move text (else copy text).
							/A    			-	Append text (else erase old buffer).
							/E    			- Erase buffer, perform no move or copy.
							/O=1 	 			- The marked block will be turned turned off after the
													  operation.
   						/I=1	 			- Cut block only if cursor in block (else cut line).
							/NM=1				- Show no messages
							/NEM=1		  - Will not end block marking
            	/NW=1   		- Windows version only.  Do NOT copy block of text
                    			  to Windows clipboard.
							/NW=2				- Copy text FROM the Windows clipboard
	Exit    : None.

              (C) Copyright 1991-95 by American Cybernetics, Inc.
********************************************************************( ldh )***/

	int MoveBlk 	 	= XPos( "/M", Flags, 1 );
	int Append_Buf	= XPos( "/A", Flags, 1 );
	int Erase_Buf  	= XPos( "/E", Flags, 1 );
	int BlkOff		 	= Parse_Int( "/O=", Flags );
	int InBlk			 	= Parse_Int( "/I=", Flags );
	int Message		 	= Parse_Int( "/NM=", Flags ) == 0;
  int KeepMarking = Parse_Int( "/NEM=", Flags );
	int WinCopyClip	= Parse_Int( "/NW=", Flags );
  int SavRefresh 	= Refresh;
	int SavUndo 	 	= Undo_Stat;
  int Source_Win 	= Cur_Window;
  int SavBlk     	= 0;

	int CBS = Block_Stat;
 	int SavBS;
	int SavBL1;
	int SavBL2;
	int SavBC1;

  str Buf_Name;
	str tfn = file_name;
  str Msg = "Block ";

  Refresh = False;
	Error_Level = 0;
	if(WinCopyClip == 2)
	{
		SwitchToBuffer( Buf_Num );
		Eof;
		if ( C_Col != 1 ) {
			Down;
			Goto_Col( 1 );
		}
//		Put_Line( "<<< From Windows Clipboard >>>");
//		down;
		Win3_Paste;
		File_Changed = False;
  	Switch_Window( Source_Win );
		refresh = savrefresh;
		return();
	}

		Push_Undo;

		if ( KeepMarking == 0 ) {
			KeepMarking = g_KeepBlkMarking;
		}
		if ( InBlk == 0 ) {
			InBlk = g_ChkInBlock;
		}
  	if ( InBlk == 1 ) {
    	InBlk = CursorInBlock( True );
		}
		else {
    	InBlk = Block_Stat;
		}
  	if ( !InBlk ) {
			if( cbs && persistent_blocks )
			{
    		SavBlk = PushBlock( True );
			}
			else
			{
				InBlk = 1;
			}
    	Block_Begin;
			Block_End;
    	Msg = "Line ";
		}
  	if ( KeepMarking < 1 ) {
			Block_End;
		}
  	if ( Buf_Num > 999 ) {
    	Buf_Num = 999;
		}
  	if ( Buf_Num < 0 ) {
    	Buf_Num = 0;
		}

	#ifdef Windows
		if ( !Erase_Buf ) {
  		if ( !WinCopyClip ) {
    		Return_Int = True;
	 	/*		if ( ( Block_Line2 - Block_Line1 ) > 1000 ) {
        		Rm( "Verify /BL=Confirm Large Block/T=Copy text to the Windows clipboard?" );
				}*/
				if ( Return_Int ) {
 					Win3_Copy;
				}
			}
		}
		NewClipboardData = False;
	#endif

	SwitchToBuffer( Buf_Num );
	Buf_Name = _Buffer_Name;
  if ( Erase_Buf) {
    Undo_Stat = False;
    Erase_Window;
    Undo_Stat = SavUndo;
    File_Name = Buf_Name;
		Msg = "Erased buffer " + Str( Buf_Num );
  	Set_Global_Int( "!Buffer_Active", False );
  }
	else {
  	Set_Global_Int( "!Buffer_Active", True );
		SavBS  = Block_Stat;
		SavBL1 = Block_Line1;
		SavBL2 = Block_Line2;
		SavBC1 = Block_Col1;
	 	if ( Append_Buf && SavBS ) {
    	Goto_Line( SavBL2 + 1 );
		}
		else {
			Eof;
			if ( C_Col != 1 ) {
				Down;
				Goto_Col( 1 );
			}
		}
	//	Put_Line( "<<< " + tfn + " Style=" + str(3) + " >>>");
	//	down;
    if ( MoveBlk ) {
			Window_Move( Source_Win );
			Msg += "moved to buffer " + Str( Buf_Num);
		}
		else {
			Window_Copy( Source_Win );
			if ( Append_Buf ) {
				Msg += "appended to buffer " + Str( Buf_Num );
			}
			else {
				Msg += "copied to buffer " + Str( Buf_Num );
			}
		}
		if ( Append_Buf ) {
			if ( SavBS ) {
				Block_Line1 = SavBL1;
				if ( Block_Stat != _LinBlock ) {
					Block_Col1 = SavBC1;
				}
			}
			else {
				Eof;
				Block_Begin;
				Tof;
				Block_End;
			}
		}
	}
	File_Changed = False;
  Switch_Window( Source_Win );
  if ( BlkOff || !InBlk ) {
    Block_Off;
	}
  if ( SavBlk ) {
    PopBlock( True );
	}
	if ( Message ) {
		Make_Message( Msg );
	}
  Refresh = SavRefresh;
  Pop_Undo;

}  // Cut

macro Paste trans2 {
/*******************************************************************************
																MULTI-EDIT MACRO

Name:	paste

Description: Copies block from buffer into current file.

Parameters:	/B=n		Buffer number
						/O=n  	If non-zero then the marked block will be turned turned off
										after the operation
						/A=n		In non-zero then the cursor will be placed at the end of
										the pasted block

							 (C) Copyright 1991 by American Cybernetics, Inc.
*******************************************************************************/

	int buf_num, temp_refresh, source_win, buf_win ;
	int Cursor2Eob;
	int TurnBlkOff;

	str buf_name ;

	push_undo;
	temp_refresh = refresh;
	refresh = false;
	source_win = cur_window;
	error_level = 0;

	buf_num = parse_int('/B=', Mparm_Str);
	if ( buf_num > 999 )
		buf_num = 999;
	if ( buf_num < 0 )
		buf_num = 0;
	buf_name = _BUFFER_NAME;

	#IFDEF windows

		if ( NewClipboardData )
		{
			RM("CUT /NW=2");
			NewClipboardData = FALSE;
		}

	#ENDIF

	if(  switch_file_ex(buf_name, 1) == 0  )
	{
bufferempty:
		make_message('Nothing to paste in buffer ' +str(buf_num));
		switch_window( source_win );
		goto exit;
	}

	// window_attr = $81;
	if(  block_stat == 0  )
		goto bufferempty;
	buf_win = cur_window;
	switch_window( source_win );
	window_copy( buf_win );

	call BlockPos;
	Make_Message( "Block copied from buffer " + Str( Buf_Num ) );
	if ( XPos( "/O=", MParm_Str, 1 ) ) {
		TurnBlkOff = Parse_Int( "/O=", MParm_Str );
	}
	else {
		TurnBlkOff = Global_Int( "BlockOffAfterPaste" );
	}
	if ( TurnBlkOff ) {
		Block_Off;
	}
	goto exit;

blockpos:

		int tpersist = persistent_blocks;

		Persistent_Blocks = TRUE;
		if ( XPos( "/A=", MParm_Str, 1 ) ) {
			Cursor2Eob = Parse_Int( "/A=", MParm_Str );
		}
		else {
			Cursor2Eob = Global_Int( "Cursor_Eob" );
		}
		if ( Cursor2Eob ) {
			if ( Block_Stat != _ColBlock ) {
				Rm( "EndBlock" );
			}
			switch ( Block_Stat ) {
				case _LinBlock :
					Down;
					break;

				case _ColBlock :
					Goto_Col( Block_Col2 + 1 );
					break;

				case _StrBlock :
          if ( Block_Col2 ) {
            Right;
					}
			}
		}
		persistent_blocks = tpersist;
		ret;

Exit:
	Pop_Undo;
	Refresh = Temp_Refresh;

}  // Paste

macro BLCKMATH TRANS2 {
/*******************************************************************************
																MULTI-EDIT MACRO

Name: BLCKMATH

Description:  Performs math operations on blocks of numbers.

Parameters: /O=  [ * / - +]   the math operation to perform.
												If /O= is not specified, the user will be
												prompted for the operation.
						/BC=	Amount of boxes to kill upon exit.

							 (C) Copyright 1991 by American Cybernetics, Inc.
*******************************************************************************/

	real  rx, ry ;
	str  tstr[80], operation[1] ;
	int  jx, tbc , commas, jy,Negative ,
			t_persistent_blocks = persistent_blocks;

	refresh = false;
	persistent_blocks = true;

	operation = parse_str('/O=', mparm_str );
	Commas = false;
	if(  operation == ''  ) {
		tbc = parse_int('/BC=', mparm_str);
#ifdef windows
		int dlg;

		DlgCreate(dlg);

		DlgAddCtrl(dlg, DLG_BitmapStatic, "BT_BL_114", 12, 1, 0,0,100,0, "" );
		DlgAddCtrl( dlg, DLG_BlackFrame, "", 1, Dlg_units | (DLG_Units_Per_Line + 12), 25, Dlg_units | ((DLG_Units_Per_Line ) + 4),901,0,"" );
		DlgAddCtrl(dlg, DLG_PushButton, "&+",2, 3, 5, 0, 110, 0, "/R=101");
		DlgAddCtrl(dlg, DLG_PushButton, "&-",8, 3, 5, 0, 111, 0, "/R=102");
		DlgAddCtrl(dlg, DLG_PushButton, "&*",14, 3, 5, 0, 112, 0, "/R=103");
		DlgAddCtrl(dlg, DLG_PushButton, "&/",20, 3, 5, 0, 113, 0, "/R=104");
		DlgAddCtrl(dlg, DLG_PushButton, "Close",1, 5, 8, 0, 114, 0, "/R=0");
		DlgAddCtrl(dlg, DLG_PushButton, "&Help",18, 5, 8, 0, 115, 0, "/R=2");

		return_int = DlgExecute(dlg, 110, "Select Operation","MATH OPERATION", "", 0);
		DlgKill(dlg);
		if ( return_int > 100 )
			return_int -= 100;

#else
		RM('userin^xmenu /L=Select Operation/B=1' + mparm_str +
				'/M=+  (BLOCKMATH)-  ()*  ()/  ()');
#endif

		if(  return_int < 1  ) {
			goto exit;
		}
		operation = copy('+-*/', return_int, 1 );
#ifndef Windows
		while(  box_count > tbc  ) {
			kill_box;
		}
#endif
	}

	Push_Undo;
	mark_pos;
	if(  marking  ) {
		block_end;
	}
	rx = 0.0;
	jx = 0;
	goto_line( block_line1 );
	if(  block_stat == 2  ) {
		while(  (c_line <= block_line2)  ) {
			goto_col( block_col1 );
	 col_again:
			while(  NOT(at_eol) &
						(XPOS(cur_char,'0123456789-.',1) == 0) &
						(c_col < block_col2)  ) {
				RIGHT;
			}
			if(  (c_col <= block_col2)  ) {
				tstr = get_word_in( '0123456789.-,' );
				call perform_operation;
				if(  (c_col < block_col2) & NOT( at_eol )  ) {
					goto col_again;
				}
			}
			down;
		}
	} else {
		goto_col( 1 );
		goto_col( block_col1 );
		if(  (block_stat == 1) | (block_stat == 3)  ) {
			while(  (c_line <= block_line2)  ) {
				while(  NOT(at_eol) &
							(XPOS(cur_char,'0123456789-.',1) == 0)
							 ) {
					RIGHT;
				}
				if(  (at_eol) | ( (c_line == block_line2) & (c_col > block_col2))  ) {
					down;
					first_word;
				} else {
					tstr = get_word_in( '0123456789.-,' );
					call perform_operation;
				}
			}
		}
	}
	goto_mark;
	tstr = rstr( rx, 0, 10 );
	if(  xpos( '.', tstr, 1 )  ) {
		while(  (copy( tstr, svl(tstr),1 ) == '0')  ) {
			tstr = copy( tstr, 1, svl(tstr) - 1 );
		}
		if(  (copy( tstr, svl(tstr),1 ) == '.')  ) {
			tstr = copy( tstr, 1, svl(tstr) - 1 );
		}
	}
	if(  (Commas)  ) {
		Negative = (Xpos('-',Tstr,1) > 0);
		Jx = Xpos('.',Tstr,1);
		if(  (Jx == 0)  ) {
			Jx = Svl(tstr);
		} else {
			--jx;
		}
		Jx = Jx - Negative;
		Jy = (jx / 3) - ((Jx % 3) == 0);
		while(  (Jy)  ) {
			tstr = Str_Ins(',',tstr,(jx - (Jy * 3)) + 1 + Negative);
			++jx;
			--Jy;
		}
	}
	if ( !t_persistent_blocks ) {
		int source_window = cur_window;
		switch_window(window_count);
		create_window;
		put_line(tstr);
		tof;
		str_block_begin;
		eof;
		rm('cut');
		delete_window;
		switch_window(source_window);
	} else {
		text( tstr );
	}
	Pop_Undo;
	goto exit;

perform_operation:
remove_commas:
	Jy = XPos(',',Tstr,1);
	if(  (Jy)  ) {
		Commas = True;
		Tstr = Str_Del(TStr,Jy,1);
		Goto REMOVE_COMMAS;
	}
	if(  rval( ry, tstr ) == 0  ) {
		++jx;
		if(  jx == 1  ) {
			rx = ry;
		} else {
			if(  operation == '+'  ) {
				rx = rx + ry;
			}
			if(  operation == '*'  ) {
				rx = rx * ry;
			}
			if(  operation == '-'  ) {
				rx = rx - ry;
			}
			if(  operation == '/'  ) {
				rx = rx / ry;
			}
		}
	}
	ret;
exit:
	persistent_blocks = t_persistent_blocks;
}