macro_file MEUTIL2;


#define LINBLOCK		1
#define COLBLOCK		2
#define STRBLOCK		3

#ifdef windows
#include metools.sh
#include winsmall.sh
#include mew_dlgs.sh
#include dialog.sh
#else
#include metools.sh
#endif

Global
{
	int reg_exp_style;    // TRUE = Unix style expressions
}

/*******************************************************************************
														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 (!(Global_Int ('!BUFFER_ACTIVE') || Win3_Clipboard));
}
int CheckMarking ()
{
  return (marking != 0);
}
int CheckNoMarking ()
{
  return (marking == 0);
}

int CheckLineMarking ()
{
  return (Global_Int ('@LAST_BLOCK_TYPE') == 1);
}
int CheckColMarking ()
{
  return (Global_Int ('@LAST_BLOCK_TYPE') == 2);
}
int CheckStrMarking ()
{
  return (   (Global_Int ('@LAST_BLOCK_TYPE') == 3)
          || (Global_Int ('@LAST_BLOCK_TYPE') == 0) );
}

macro UNDBLK TRANS2 {
/*******************************************************************************
																MULTI-EDIT MACRO

Name:	UNDBLK

Description:	Undents the current marked block starting and ending
							at the top and bottom lines of the marked block.

							 (C) Copyright 1991 by American Cybernetics, Inc.
*******************************************************************************/
	int jx,j1, EndLine = Block_Line2,
			t_block_stat = block_stat,
			t_refresh = refresh;

	if ( Block_Stat )
	{
		Working;
		Push_Undo;
		block_end;
		if(( block_stat == 3) && (block_col2 < 1))
			--EndLine;
		Refresh = False;
		Mark_Pos;
		Goto_Line(Block_Line1);
		while ( C_Line <= EndLine )
		{
			First_Word;
			J1 = C_Col;
			Tab_Left;
			if ( AT_EOL == FALSE )
					Del_Chars(j1 - C_Col);
			DOWN;
		}

		Goto_Mark;
		block_stat = t_block_stat;
		Pop_Undo;
	}
	refresh = t_refresh;
	redraw;
}

macro INDBLK TRANS2 {
/*******************************************************************************
																MULTI-EDIT MACRO

Name:	INDBLK

Description:	Indents the current marked block starting and ending
							at the top and bottom lines of the marked block.

							 (C) Copyright 1991 by American Cybernetics, Inc.
*******************************************************************************/
	int Temp_Ins = Insert_Mode, EndLine = Block_Line2,
			t_block_stat = block_stat,
			t_refresh = refresh;

	if ( Block_Stat )
	{
		Push_Undo;
		block_end;
		if(( block_stat == 3) && (block_col2 < 1))
				--EndLine;
		Insert_Mode = True;
		Refresh = False;
		Mark_Pos;
		Goto_Line(Block_Line1);
		while ( C_Line <= EndLine )
		{
			// First_Word;
			goto_col(1);
			if ( !At_Eol )
			{
				Tab_Right;
			}
			DOWN;
		}

		Insert_Mode = Temp_Ins;
		Goto_Mark;
		block_stat = t_block_stat;
		Pop_Undo;
	}
	refresh = t_refresh;
	redraw;
}

macro MarkBlck trans2 {
/*******************************************************************************
																MULTI-EDIT MACRO

Name:	MarkBlck

Description:	Starts and stops line oriented block marking.

Parameters:  /O=n  If non-zero does not turn block off if existing
									 block is not a line oriented block.

							 (C) Copyright 1991 by American Cybernetics, Inc.
*******************************************************************************/
	int BlockLN1 = Block_Line1, BlockLN2 = Block_Line2;

	if ( Marking )
	{
		if ( Parse_Int("/O=", MParm_Str) )
		{
			if ( LINBLOCK == Block_Stat )
			{
				Set_Global_Int("!SmartBlock", 0);
				Block_Off;
				Make_Message('Block turned off.');
			}
			else
			{
				Refresh = false;
				Block_Off;
				if ( C_Line != BlockLN1 )
				{
					Goto_Line(BlockLN1);
					Block_Begin;
					Goto_Line(BlockLN2);
				}
				else
				{
					Goto_Line(BlockLN2);
					Block_Begin;
					Goto_Line(BlockLN1);
				}
				Redraw;
			}
		}
		else
		{
			Set_Global_Int("!SmartBlock", 0);
			BLOCK_END;
			Make_Message('Block marked.');
		}
	}
	else
	{
		Set_Global_Int("!SmartBlock", 0);
		BLOCK_BEGIN;
	}
}

macro MColBlck trans2 {
/*******************************************************************************
																MULTI-EDIT MACRO

Name:	MColBlck

Description:	Starts and stops column oriented block marking.

Parameters:  /O=n  If non-zero does not turn block off if existing
									 block is not a column oriented block.

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

	int BlockLN1 = Block_Line1, BlockLN2 = Block_Line2, BlockCL1,
			BlockCL2 = C_Col;

	if ( Marking )
	{
		if ( Parse_int("/O=", MParm_Str) )
		{
			if ( COLBLOCK == Block_Stat )
			{
				Set_Global_Int("!SmartBlock", 0);
				Block_Off;
				Make_Message('Block turned off.');
			}
			else
			{
				Refresh = False;
				Block_Off;
				if ( 0 != (BlockCL1 = Global_Int("!SmartBlock")) )
					Goto_Col(BlockCL1);
				else
					Set_Global_Int("!SmartBlock", C_Col);
				if ( BlockLN1 != C_Line )
				{
					Goto_Line(BlockLN1);
					Col_Block_Begin;
					Goto_Line(BlockLN2);
				}
				else
				{
					Goto_Line(BlockLN2);
					Col_Block_Begin;
					Goto_Line(BlockLN1);
				}
				Goto_Col(BlockCL2);
				Refresh = True;
				Redraw;
			}
		}
		else
		{
			BLOCK_END;
			Set_Global_Int("!SmartBlock", 0);
			Make_Message('Block marked.');
		}
	}
	else
	{
		Set_Global_Int("!SmartBlock", C_Col);
		COL_BLOCK_BEGIN;
	}
}

macro MStrBlck trans2 {
/*******************************************************************************
																MULTI-EDIT MACRO

Name:	MStrBlck

Description:	Starts and stops stream oriented block marking.

Parameters:  /O=n  If non-zero does not turn block off if existing
									 block is not a stream oriented block.

							 (C) Copyright 1991 by American Cybernetics, Inc.
*******************************************************************************/
	int BlockLN1 = Block_Line1, BlockLN2 = Block_Line2, BlockCL1,
			BlockCL2 = C_Col;

	if ( Marking )
	{
		if ( Parse_int("/O=", MParm_Str) )
		{
			if ( STRBLOCK == Block_Stat )
			{
				Set_Global_Int("!SmartBlock", 0);
				Block_Off;
				Make_Message('Block turned off.');
			}
			else
			{
				Refresh = False;
				Block_Off;
				if ( 0 != (BlockCL1 = Global_Int("!SmartBlock")) )
					Goto_Col(BlockCL1);
				else
					Set_Global_Int("!SmartBlock", C_Col);
				if ( BlockLN1 != C_Line )
				{
					Goto_Line(BlockLN1);
					Str_Block_Begin;
					Goto_Line(BlockLN2);
				}
				else
				{
					Goto_Line(BlockLN2);
					Str_Block_Begin;
					Goto_Line(BlockLN1);
				}
				Goto_Col(BlockCL2);
				Refresh = True;
				Redraw;
			}
		}
		else
		{
			BLOCK_END;
			Set_Global_Int("!SmartBlock", 0);
			Make_Message('Block marked.');
		}
	}
	else
	{
		Set_Global_Int("!SmartBlock", C_Col);
		STR_BLOCK_BEGIN;
	}
}

macro BLOCKOFF TRANS2 {
/*******************************************************************************
																MULTI-EDIT MACRO

Name:	BLOCKOFF

Description:	Turns the current block marking off.

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

	if(  BLOCK_STAT > 0  ) {
		Block_Off;
		Make_Message('Block turned off.');
	} else {
		Make_Message('No Block Marked.');
	}
}


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 getuserpath( ) + 'BUFFER.' + Str(Buf_Num)

void SwitchToBuffer( int buf_num ) trans2
{
	str buf_name = _BUFFER_NAME;
	if ( switch_file( buf_name) == 0 )
	{
		switch_window(window_count);
		create_window;
		if(  error_level != 0  )
			return();
		window_attr = $81;
		file_name = buf_name;
	}
}




/****************** 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 clipEventProc( int m )
{
	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 );
        break;
        #ENDIF
  }
	persistent_blocks = t_persistent_blocks;
	if(window_id == tw)
	{
    window_name = 'BUFFER';
    file_changed = false;
	}
	else
	{
		int tr = refresh,
				tw2 = cur_window;

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

  return(0);

}

/******************** 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*******************************/
void ShowClipboard( int buf_num = parse_int('/B=', mparm_str))
{
	int twin = window_id;

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

	if(switch_file( _BUFFER_NAME  ))
	{
		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;
			window_name = 'BUFFER';
			window_attr = 0x80;
      Make_Window_Visible (1);
			redraw;
		}
		else
		{
			event_macro  = '';
      event_mode = 0;
			window_attr = 0x81;
      Make_Window_Visible (0);
			switch_win_id(global_int('!CLIP_OLD_WIN'));
			rm("FINDWIN");
			set_global_int('!CLIP_OLD_WIN', 0 );
			set_global_int('!CLIP_SHOW', 0 );
		}

	}
}

macro CUT TRANS2 {
/*******************************************************************************
																MULTI-EDIT MACRO

Name: CUT

Description:  Copies, Moves or Appends text into a hidden buffer.

Parameters:  /M    Move text (else copy text)
						 /A    Append text (else erase old buffer);
						 /B=n  n = the buffer # (0 is the default);
						 /E    Erase buffer, perform no move or copy
						 /O=n  If non-zero then the marked block will be turned
									 turned off after the operation

							/NW=1  Windows version only.  Do NOT copy block of text
										 to Windows clipboard.

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

	int  buf_num, temp_refresh, source_win, erase_buf, Append_buf, t_block_stat ;
	str  buf_name, msg = 'Block ';
	int	 tc1,tc2, tl1,tl2, ts, tundo = undo_stat;

	temp_refresh = refresh;
	push_undo;
	refresh = false;
	source_win = cur_window;
	error_level = 0;
	t_block_stat = block_stat;
	if ( !Block_Stat )
	{
			Block_Begin;
			msg = 'Line ';
	}
	block_end;
	erase_buf = XPOS('/E', MParm_Str, 1);
	append_buf = XPOS('/A', MParm_Str, 1);
	buf_num = parse_int('/B=', Mparm_Str);
	if ( buf_num > 999 )
		buf_num = 999;
	if(  buf_num < 0  )
		buf_num = 0;


	#IFDEF windows
		if ( !parse_int("/NW=", mparm_str) )
		{
			return_int = TRUE;
			if( (block_line2 - block_line1) > 300 )
			{
         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 = file_name;

	if(erase_buf)
	{
		undo_stat = false;
		erase_window;
		undo_stat = tundo;
		file_name = buf_name;
		set_global_int("!BUFFER_ACTIVE", 0 );
	}
	else
	{
		set_global_int("!BUFFER_ACTIVE", 1 );
	}

	ts = block_stat;
	tc1 = block_col1;
	tc2 = block_col2;
	tl1 = block_line1;
	tl2 = block_line2;

	if(  append_buf && ts  )
	{
		goto_line(tl2 + 1);

	}
	else
	{
		eof;
		if(  (c_col != 1)  )
		{
			down;
			goto_col(1);
		}
	}

	 /* TMJ - 07-07-93 01:16pm
		if(  (append_buf == 0) | (erase_buf)  )
		{
			Erase_Window;
			file_name = buf_name;
		}
		else
		{
			EOF;
			if(  (c_col != 1)  )
			{
				down;
				goto_col(1);
			}
		}

		*/

	if(  erase_buf == 0  )
	{
//		if(  t_block_stat == 0  )
//		{
//			make_message('No block marked.');
//			goto exit;
//    }
		if(  XPos('/M', MParm_Str,1) == 0  )
		{
			Window_Copy(source_win);
			if(  append_buf  )
				Make_Message(msg+'appended to buffer ' + Str(buf_num));
			else
				Make_Message(msg+'copied to buffer ' + Str(buf_num));
		}
		else
		{
			Window_Move(source_win);
			Make_Message(msg+'moved to buffer ' + Str(buf_num));
		}
		if(  append_buf  )
		{
			if(ts)
			{
				block_line1 = tl1;
				if(block_stat != 1)
					block_col1 = tc1;
			}
			else
			{
				eof;
				block_begin;
				tof;
				block_end;
			}
		}
	}
	else
		Make_Message('Erased buffer ' + str(buf_num));

	file_changed = false;
exit:
	switch_window( source_win );
	if ( Parse_Int("/O=", MParm_Str) )
		Block_Off;
	pop_undo;
	refresh = temp_refresh;
}

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


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

	int  buf_num, temp_refresh, source_win, buf_win ;
	str  buf_name ;

  #IFDEF windows

    if ( NewClipboardData )
    {
			Win3_Paste;
			RM("CUT /NW=1");
			call blockpos;
			NewClipboardData = FALSE;
			make_message("Text pasted from Windows' clipboard.");
      if( global_int("BlockOffAfterPaste"))
      {
        block_off;
      }
      return();
    }

  #ENDIF


	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;

	if(  switch_file(buf_name) == 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( global_int("BlockOffAfterPaste"))
  {
    block_off;
  }
	goto exit;

blockpos:
		int tpersist = persistent_blocks;
		persistent_blocks = TRUE;
		if( global_int("CURSOR_EOB"))
		{
			if( block_stat != 2 )
				rm("ENDBLOCK");
			switch ( block_stat )
			{
				case 1 :
					down;
					break;
				case 2 :
					goto_col( block_col2 + 1 );
					break;
				case 3 :
					right;

			}
		}
		else
		{

		}
		persistent_blocks = tpersist;
		ret;

exit:
	if ( Parse_Int("/O=", MParm_Str) )
		Block_Off;
	pop_undo;
	refresh = temp_refresh;
}

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;
}