/*****************************************************************************

  TCEditor class by SET, copyright (c) 1996.

    This file can be used by Robert Hhne for his RHIDE, any other use
  needs the permission of the author.

  E-Mail: salvador@inti.edu.ar
  
  Telephone: (+541) 759-0013
  
  Postal Address:
  Salvador E. Tropea
  Curapalige 2124
  (1678) Caseros - 3 de Febrero
  Prov: Buenos Aires
  Argentina

  Contributors:
  Robert Hhne    (Robert.Hoehne@Mathematik.TU-Chemnitz.DE)
  Marek Habersack (grendel@ananke.amu.edu.pl)
  Molnar Laszlo   (molnarl@postabank.hu)

*****************************************************************************/

// That's the first include because is used to configure the editor.
#include "ceditint.h"

#define Uses_TKeys
#define Uses_TIndicator
#define Uses_TEvent
#define Uses_TScrollBar
#define Uses_TFindCDialogRec
#define Uses_TReplaceCDialogRec
#define Uses_TReplaceDialogRec
#define Uses_opstream
#define Uses_ipstream
#define Uses_TStreamableClass
#define Uses_TMacroCollection
#define Uses_TStringCollection
#define Uses_MsgBox
#define Uses_TGroup
#define Uses_TPalette
#define Uses_TCommandSet
#include <tv.h>

#define Uses_TCEditor
#define Uses_LineLengthArray
#include "ceditor.h"

#include "setconst.h"

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#ifndef __GNUC__
#include <malloc.h>
#endif

#define DEBUG

#ifdef DEBUG
# define MyAssert(p) ((p) ? (void)0 : (void) printf( \
                    "Assertion failed: %s, file %s, line %d\n", \
                    #p, __FILE__, __LINE__ ),getch(),abort() )
#else
# define MyAssert(p) ((void)0)
#endif

#ifndef __GNUC__
# ifdef DEBUG
#   define BCC_DEBUG
# endif
#endif

#ifdef BCC_DEBUG
# include <alloc.h>
# include <conio.h>
#define TEST_SPLINES
#endif


extern char *ExpandFileNameToThePointWhereTheProgramWasLoaded(char *s);

// This function is inline but isn't a macro to avoid the side efects
inline int isWordChar( int ch )
{
    return isalnum(ch) || ch == '_';
}

#define CutIfNotPersistent()    if (!PersistentBlocks && hasSelection()) \
                                   clipCut()
#define ClearSelIfNonPers()     { if (!PersistentBlocks && hasSelection()) \
                                    { \
                                     selEnd=selStart=0; \
                                     update(ufView); \
                                    } \
                                }

#define CheckForShiftSelection() { \
		    if (selectMode==smStartSel && NotExpandingMacro &&           \
			event.message.command!=cmcExpandCode)                    \
		      {                                                          \
		       if (IslineInEdition)                                      \
			  MakeEfectiveLineInEdition();                           \
		       SetStartOfSelecting((uint32)(ColToPointerPost()-buffer)); \
		       selectMode = smExtend;                                    \
		      }    }

// New Palette from Robert.
#define cpEditor "\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"\
	 	 "\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B"
/* colors for the editor
  1 : normal text
  2 : marked text
  3 : comment
  4 : reserved word
  5 : identifier
  6 : symbol
  7 : string
  8 : integer
  9 : float
 10 : octal
 11 : hex
 12 : character
 13 : preprocessor
 14 : illegal char
 15 : user defined word
 16 : CPU line ( in RHIDE )
 17 : Breakpoint ( in RHIDE )
 18 : binary operators
 19 : cross cursor
 20 : status line
 21 : match-pair highlight
 22 : rectangular selection
*/

static uint16 LineMeassureC(char *s, char *end, uint16 &Attr);
static uint16 LineMeassurePascal(char *s, char *end, uint16 &Attr);
static uint16 LineMeassureClipper(char *s, char *end, uint16 &Attr);

/****************************************************************************

   Pseudo Macros

****************************************************************************/

// Triggers
static char CodesToReplace[64];
static uint16 ModesOfPM[32];

static int CantCodes=0;
static int ClassInitialized=0;

// Text of the pseudo-macros
static char *TextToPut[32];

ushort defEditorDialog( int, ... );


static int MeassureTriLine(char *b,unsigned &s,unsigned &e)
{
 int l;
 int in_slash=0;
 char *p=b;

 for (; *b && *b!='"'; b++);
 if (*b==0) return -1;
 s=(unsigned)(b-p);
 b++;
 for (l=0; *b && (*b!='"' || in_slash); b++)
    {
     if (*b=='\\')
        in_slash=1;
     else
       {
        in_slash=0;
        l++;
       }
    }
 if (*b==0) return -2;
 e=(unsigned)(b-p);
 return l;
}

Boolean LoadPseudoMacroFile(char *name)
{
 FILE *f;
 char buf[256];
 char *sep="\"",*s;
 int Trs=0,partial;
 unsigned l,start,end,total=0;
 unsigned mode,bit;

 if ((f=fopen(name,"rt"))==NULL)
    return False;

 fgets(buf,250,f);
 do
  {
   if (buf[0]==0 || buf[0]==';' || buf[0]=='\n')
     {
      fgets(buf,250,f);
      continue;
     }
   if (strncmp(buf,"Trigger:",8)!=0)
     {
      messageBox(_("Macro definition don't start with Trigger"),mfError | mfOKButton);
      fclose(f);
      return False;
     }
   strtok(buf,sep);
   s=strtok(NULL,sep);
   if (s==NULL || strlen(s)!=2)
     {
      messageBox(_("Missing Trigger sequence or too short"),mfError | mfOKButton);
      fclose(f);
      return False;
     }
   CodesToReplace[Trs<<1]=s[0];
   CodesToReplace[(Trs<<1)+1]=s[1];

   // Process the mode keyword
   fgets(buf,250,f);
   if (strncmp(buf,"Mode:",5)!=0)
     {
      messageBox(_("Macro definition without mode keyword"),mfError | mfOKButton);
      fclose(f);
      return False;
     }
   for (s=buf+5; *s!=0 && isspace(*s); s++);
   for (l=0,mode=0,bit=1; l<5; l++,bit<<=1)
      {
       if ((*s!='0' && *s!='1') || (l!=4 && s[1]!=','))
         {
          messageBox(_("Wrong mode definition in pseudo macro."),mfError | mfOKButton);
          fclose(f);
          return False;
         }
       if (*s=='1')
          mode|=bit;
       s+=2;
      }
   ModesOfPM[Trs]=mode;

   l=0;
   while (!feof(f))
     {
      fgets(buf,250,f);
      if (feof(f)) break;
      if (buf[0]==0 || buf[0]==';' || buf[0]=='\n')
         continue;
      if (buf[0]=='T') break;
      partial=MeassureTriLine(buf,start,end);
      switch (partial)
        {
         case -1:
              messageBox(_("Missing start in pseudo macro"),mfError | mfOKButton);
              fclose(f);
              return False;

         case -2:
              messageBox(_("Missing end in pseudo macro"),mfError | mfOKButton);
              fclose(f);
              return False;

         default: l+=partial;
        }
     }
   if (l==0)
     {
      messageBox(_("Empty pseudo macro"),mfError | mfOKButton);
      fclose(f);
      return False;
     }
   Trs++;
   total+=l+1;
  }
 while (!feof(f));

 CantCodes=0;
 if (Trs && total)
   {
    char *s;

    if ((s=(char *)malloc(total))==NULL)
      {
       fclose(f);
       return False;
      }
    rewind(f);
    fgets(buf,250,f);
    do
     {
      if (buf[0]==0 || buf[0]==';' || buf[0]=='\n')
        {
         fgets(buf,250,f);
         continue;
        }
      TextToPut[CantCodes]=s;
      while (!feof(f))
        {
         fgets(buf,250,f);
         if (feof(f)) break;
         if (buf[0]==0 || buf[0]==';' || buf[0]=='\n')
            continue;
         if (buf[0]=='T') break;
         if (buf[0]=='M') continue;
         MeassureTriLine(buf,start,end);
         int in_slash;
         for (in_slash=0,l=start+1; l<end; l++)
            {
             if (!in_slash && buf[l]=='\\')
                in_slash=1;
	     else
               {
                if (in_slash)
                  {
                   in_slash=0;
                   switch (buf[l])
                     {
                      case 'a': *s='\a';
                                break;
                      case 'f': *s='\f';
                                break;
                      case 'v': *s='\v';
                                break;
                      case '\\': *s='\\';
                                break;
                      case 'n': *s='\n';
                                break;
                      case 'b': *s='\b';
                                break;
                      case 't': *s='\t';
                                break;
                      default: *s=buf[l];
                     }
                  }
                else
                   *s=buf[l];
                s++;
               }
	    }
        }
      *(s++)=0;
      CantCodes++;
      total+=l+1;
     }
    while (!feof(f));
   }

 fclose(f);
 return True;
}


/****************************************************************************

   Function: uint16 scanKeyMap( const void *keyMap, int keyCode )

   Type: Static function.

   Objetive: Searchs in the keyMap table the selected keyCode.
	     The match is when the 8 low bits of the keyCode matchs with an
   entry in the table and the high bits of the entry are 0 or when all the
   bits match.

   Returns: The command associated with the keyCode or 0 if does not exist.

   by SET.

****************************************************************************/
/* Obsolet
//#define KeyMap ((const ushort far *)(keyMap))

ushort scanKeyMap( const void *keyMap, int keyCode )
#ifdef __GNUC__
{
 ushort ret asm ("%ax");

 asm ( "movl %k1,%%esi   \n\t"
       "movw %w2,%%dx    \n\t"
       "cld              \n\t"
       "lodsw            \n\t"
       "movw %%ax,%%cx   \n"
"1:                      \n\t"
       "lodsw            \n\t"
       "movw %%ax,%%bx   \n\t"
       "lodsw            \n\t"
       "cmpb %%dl,%%bl   \n\t"
       "jne  3f          \n\t"
       "orb  %%bh,%%bh   \n\t"
       "je   4f          \n\t"
       "cmpb %%dh,%%bh   \n\t"
       "je   4f          \n"
"3:                      \n\t"
       "loop 1b          \n\t"
       "movw $0,%w0      \n"
"4:                      \n\t"
       : "=r" (ret) : "m" (keyMap), "m" (keyCode) : "%dx","%bx","%cx","%esi" );

 return ret;
}
#else
#pragma warn -asc
{
asm {
    PUSH DS
    LDS SI,keyMap
    MOV DX,keyCode
    CLD
    LODSW
    MOV CX,AX
    }
__1:
asm {
    LODSW
    MOV BX,AX
    LODSW
    CMP BL,DL
    JNE __3
    OR  BH,BH
    JE  __4
    CMP BH,DH
    JE  __4
    }
__3:
asm {
    LOOP    __1
    XOR AX,AX
    }
__4:
asm POP DS
    return _AX;
}
#pragma warn .asc
#endif
*/


/****************************************************************************

   Function: int InitTCEditor(char *s,Boolean force)

   Type: Normal function.

   Objetive: Intialize all the things needed by the class.
	     The function is automagically called by the constructor if never
   was called but can be called by hand to force some things.

   Things that this function make:
   1) Loads the pseudo macros file.
   2) Creates the pseudo hash tables for the reserved words (if STANDALONE).

   Parameters:
   char *s: The name of the Pseudo Macros file.
   Boolean force: If true forces the initialization.

   Returns:
   0 if all OK or the class is allready initialized.
   Flags:
   1 The Pseudo macros couldn't be loaded.

   by SET.

****************************************************************************/

int InitTCEditor(char *s,Boolean force)
{
 int ret=0;

 if (!ClassInitialized || force)
   {
    if (LoadPseudoMacroFile(ExpandFileNameToThePointWhereTheProgramWasLoaded(s))==False)
       ret|=1;
#ifdef STANDALONE
    CreateSHShortCutTables();
#endif

    ClassInitialized=1;
   }

 return ret;
}


/****************************************************************************

   Function: TCEditor( const TRect& bounds,TScrollBar *aHScrollBar,
		  TScrollBar *aVScrollBar,TIndicator *aIndicator,
		  uint32 aBufSize )

   Type: TCEditor member.

   Objetive: Constructor of the Class

   Parameters:
   TRect &bounds: Original size and location for the editor.
   TScrollBar *aHScrollBar
   TScrollBar *aVScrollBar
   TIndicator *aIndicator:  Pointers to objects for scroll bars & info.
   uint32 aBufSize: Starting size of the editor buffer.

   by SET

****************************************************************************/

TCEditor::TCEditor( const TRect& bounds,
		  TScrollBar *aHScrollBar,
		  TScrollBar *aVScrollBar,
		  TIndicator *aIndicator,
		  uint32 aBufSize ) :
    TViewPlus( bounds ),
    hScrollBar( aHScrollBar ),
    vScrollBar( aVScrollBar ),
    indicator( aIndicator ),
    bufSize( aBufSize ),
    canUndo( True ),
    selecting( False ),
    overwrite( False ),
    lockCount( 0 ),
    keyState( 0 ),
    bufEdit( 0 ),         // Not buffer allocated
    bufEditLen( 0 ),       // zero length
    ForceSelection( 0 ),
    Recording( False ),
    MacroCount( 0 ),
    CrossCurInCacheC( False ),
    CrossCurInCacheR( False ),
    IsStatusLineOn( False ),
    IsFoundOn( False ),
    IsHLCOn( False ),
    SpecialLines( NULL )
{
 InitTCEditor("pmacros.txt",False);
 // Initialize the mode of edition
 UseTabs=staticUseTabs;          // Don't put Tabs, indent
 autoIndent=staticAutoIndent;
 intelIndent=staticIntelIndent;
 tabSize=staticTabSize;
 PersistentBlocks=staticPersistentBlocks;
 CrossCursorInCol=staticCrossCursorInCol;
 CrossCursorInRow=staticCrossCursorInRow;
 ShowMatchPair=staticShowMatchPair;
 TransparentSel=staticTransparentSel;
 OptimalFill=staticOptimalFill;

 TurnOnCHighLight();
 LineMeassure=LineMeassureC;

 growMode = gfGrowHiX | gfGrowHiY;
 options |= ofSelectable;
 eventMask = evMouseDown | evKeyDown | evCommand | evBroadcast;
 showCursor();
 initBuffer();
 if ( buffer != 0 )
    isValid = True;
 else
   {
    editorDialog( edOutOfMemory );
    bufSize = 0;
    isValid = False;
   }
 setBufLen(0);
}


/****************************************************************************

   Function: ~TCEditor()

   Type: TCEditor member.

   Objetive: Destructor of the Class.
	     Deletes the buffer used to edit a line.

   doneBuffer deletes the editor buffer (? Called by ~TView).

   by SET.

****************************************************************************/

TCEditor::~TCEditor()
{
 if (bufEdit)
    delete bufEdit;
}

/****************************************************************************

   Function: shutDown()

   Type: TCEditor member.

   Objetive: Just to shutdown the editor.

   From Borland's TV 1.03.

****************************************************************************/

void TCEditor::shutDown()
{
 doneBuffer();
 TView::shutDown();
}

/****************************************************************************

   Function: changeBounds( const TRect& bounds )

   Type: TCEditor member.

   Objetive: Adjust the delta in the text when the bounds of the window are
   changed.

   by SET

****************************************************************************/

void TCEditor::changeBounds( const TRect& bounds )
{
 setBounds(bounds);
 delta.x = max(0, min(delta.x, limit.x - size.x));
 delta.y = max(0, delta.y);
 if (curPos.y>=delta.y+size.y)
    delta.y=curPos.y-size.y+1;
 if (curPos.y<delta.y)
    delta.y=curPos.y;
 update(ufView);
}

/****************************************************************************

   Function: int charPos( uint32 p, uint32 target )

   Type: TCEditor member.

   Objetive: Find the X position in a line, computing the tabs. 
   
   Parameters: 
   uint32 p      Offset of the start of the line
   uint32 target Offset of destination

   Returns: The X position.
   
   by SET.

****************************************************************************/

int TCEditor::charPos( uint32 p, uint32 target )
{
 int pos = 0;
 char *cp=buffer+p;
 char *ctarget=buffer+target;

 while( cp<ctarget )
   {
    AdvanceWithTab(*cp,pos);
    cp++;
   }
 return pos;
}

/****************************************************************************

   Function: uint32 charPtr( uint32 p, int target )

   Type: TCEditor member.

   Objetive: Find the Offset in a line, computing the tabs.
   Is the reverse of charPos. 
   If the position is in a tab the pointer points to the tab.

   Parameters: 
   uint32 p      Offset of the start of the line
   int    target X position.

   Returns: Offset for this position.
   
   by SET.

****************************************************************************/

uint32 TCEditor::charPtr( uint32 p, int target )
{
 int pos = 0;
 while( (pos < target) && (p < bufLen) && (buffer[p]!='\x0D') )
   {
    AdvanceWithTab(buffer[p],pos);
    p++;
   }
 if ( pos>target )
    p--;
 return p;
}

/****************************************************************************

   Function: Boolean clipCopy()

   Type: TCEditor member.

   Objetive: Copy the selected text to the clipboard.

   Returns: True if OK.
   
   From Borland's TV 1.03.

****************************************************************************/

Boolean TCEditor::clipCopy()
{
 Boolean res = False;
 if (IslineInEdition)
    MakeEfectiveLineInEdition();
 if ( (clipboard != 0) && (clipboard != this) )
   {
    res = clipboard->insertFrom(this);
    selecting = False;
    update(ufUpdate);
   }
 return res;
}

/****************************************************************************

   Function: void clipCut()

   Type: TCEditor member.

   Objetive: Cut the selected text to the clipboard.

   From Borland's TV 1.03.

****************************************************************************/

void TCEditor::clipCut()
{
 if (IslineInEdition)
    MakeEfectiveLineInEdition();
 if ( clipCopy() )
    deleteSelect();
}

/****************************************************************************

   Function: void clipPaste()

   Type: TCEditor member.

   Objetive: Paste from the clipboard.

   Modified to avoid insertions at the limit of the line capability.

   From Borland's TV 1.03.

****************************************************************************/

void TCEditor::clipPaste()
{
 if (IslineInEdition)
    MakeEfectiveLineInEdition();
 if ( (clipboard != 0) && (clipboard != this) && curPos.x<(MaxLineLen-1))
    insertFrom(clipboard);
}

/****************************************************************************

   Function: Boolean clipReplace()

   Type: TCEditor member.

   Objetive: Cut to clipboard and paste from clipboard.

   by SET.

****************************************************************************/

Boolean TCEditor::clipReplace()
{
 if (IslineInEdition)
    MakeEfectiveLineInEdition();
 if ( (clipboard != 0) && (clipboard != this) )
   {
    if (clipboard->insertBuffer( buffer, selStart, selEnd-selStart, canUndo, False, False ))
      {
       deleteSelect();
       return insertFrom(clipboard);
      }
   }
 return False;
}


/****************************************************************************

   Function: getshiftstate() alias shiftkeys()

   Type: Static function.

   Objetive: Ask to the BIOS the current state of shift+control+alt.

   GNU version by Robert Hhne (is in event.cc).
   BCC version by SET.
   NonBIOS by SET.

****************************************************************************/

#define shiftkeys() getshiftstate()
#ifdef BIOS_KEYBOARD
#ifdef __GNUC__

#ifdef USE_BIOS_FOR_SHIFT
extern uint16 getshiftstate(void);
#else
// A faster implementation
inline uint16 getshiftstate(void)
{
 ushort shifts;
 _dosmemgetw(0x417,1,&shifts);
 return shifts;
}
#endif

#else
static uint16 getshiftstate(void)
{
 const uchar far *const shiftState = (uchar far *)MK_FP( 0x40, 0x17 );
 return *shiftState;
}
#endif
#define kbFlagsShift (kbRightShift | kbLeftShift)
#define kbCtrlFlg    kbCtrlShift
#define kbAltFlg     kbAltShift
#define kbShiftFlg   kbFlagsShift

#else

// here by now
extern int _shifts_flags;
#define kbShiftFlg    1
#define kbCtrlFlg     2
#define kbAltFlg      4
#define kbCapsLockFlg 8
#define kbNumLockFlg  16
#define kbScroLockFlg 32
#define getshiftstate() _shifts_flags
#define kbFlagsShift kbShiftFlg

#endif

/****************************************************************************

   Function: void convertEvent( TEvent& event )

   Type: TCEditor member.

   Objetive: Translate a key convination to a command.

   Parameters:
   TEvent& event: The event.

   by SET.

   ToDo: CleanUp the situation, is very patched.

****************************************************************************/

/*
void TCEditor::convertEvent( TEvent& event )
{
 if( event.what == evKeyDown )
     {
     #ifdef OriginalKeyboard
     if (shiftkeys() & 0x03)
       {
	uchar c=event.keyDown.charScan.scanCode;
	if (c>=0x47 && c<=0x51)
	   event.keyDown.charScan.charCode = 0;
	else
	   if (c==0x94)
	      event.keyDown.charScan.charCode = 0x10;
	else
	  {
	   c=event.keyDown.charScan.charCode;
	   if (c==0x20)
	      event.keyDown.charScan.scanCode = 1;
	  }
       }
     #endif //OriginalKeyboard

     ushort key = event.keyDown.keyCode;
     if( keyState != 0 )
	 {
	  switch (key)
	    {
	     case 0x0F09: // Tab
	     case 0x0F00: // Shift Tab
			  break;
	     default:
		// Take the char code
		key &= 0xFF;
		// Is Ctrla-Ctrl z?
		if( key>=0x01 && key<=0x1A )
		    key += 0x40;
		// Is CtrlA-CtrlZ?
		if( key>=0x61 && key<=0x7A )
		    key -= 0x20;
	    }
	 }

     key = scanKeyMap(keyMap[keyState], key);

     keyState = 0;
     if( key != 0 )
	 if( (key & 0xFF00) == 0xFF00 )
	     {
	     keyState = (key & 0xFF);
	     clearEvent(event);
	     }
	 else
	     {
	     event.what = evCommand;
	     event.message.command = key;
	     }
     }
}
*/

#ifdef BIOS_KEYBOARD
// This table makes the reverse thing that BIOS
static char KeybTranslator[256] = {
// 0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 0
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 1
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 2
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 3
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 4
   0,   0,   0,   0,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x3B,0x3C,  // 5
0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,  // 6
0x43,0x44,   0,0x4B,0x4D,0x4F,0x51,0x47,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,  // 7
0x0A,0x0B,   0,   0,0x49,0x57,0x58,0x57,0x58,0x57,0x58,0x57,0x58,0x48,0x4A,0x4C,  // 8
0x4E,0x50,0x52,0x53,0x0F,0x35,0x37,0x47,0x48,0x49,   0,0x4B,   0,0x4D,   0,0x4F,  // 9
0x50,0x51,0x52,0x53,0x35,0x0F,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // A
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // B
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // C
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // D
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // E
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // F
};

// That's the extra info loosed when I reverse the bios translation
static char KeybShifter[256] = {
// 0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 0
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 1
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 2
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 3
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 4
   0,   0,   0,   0,   3,   3,   3,   3,   3,   3,   3,   3,   3,   3,   4,   4,  // 5
   4,   4,   4,   4,   4,   4,   4,   4,   8,   8,   8,   8,   8,   8,   8,   8,  // 6
   8,   8,   0,   4,   4,   4,   4,   4,   8,   8,   8,   8,   8,   8,   8,   8,  // 7
   8,   8,   0,   0,   4,   0,   0,   3,   3,   4,   4,   8,   8,   4,   0,   0,  // 8
   0,   4,   4,   4,   4,   0,   0,   8,   8,   8,   0,   8,   0,   8,   0,   8,  // 9
   8,   8,   8,   8,   8,   8,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // A
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // B
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // C
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // D
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // E
   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // F
};
#endif

void TCEditor::convertEvent( TEvent& event )
{
 if ( event.what == evKeyDown )
   {
#ifdef __GNUC__
    int S=event.keyDown.shiftState;
#else
    int S=shiftkeys();
#endif

#ifdef BIOS_KEYBOARD
#ifdef __GNUC__
    uchar c=event.keyDown.raw_scanCode;
#else
    uchar c=event.keyDown.charScan.scanCode;
#endif
    uchar c2=KeybTranslator[c];
    if (c2)
      {
       S|=KeybShifter[c];
       c=c2;
      }
    else
      {
       if (c>0x7F)
          c=0x7F;
      }
#else
    uchar c=event.keyDown.charScan.scanCode & 0x7F;
#endif
    unsigned key=0;

    switch (keyState)
      {
       case 0: if (!(S & kbAltFlg))
                 { // Ignore all Alt keys
                  if (S & kbCtrlFlg)
                    { // Ctrl
                     if (S & kbShiftFlg)
                        key=kbFunShiftCtrl[c];
                     else
                        key=kbFunCtrl[c];
                    }
                  else
                  if (S & kbShiftFlg)
                     key=kbFunShift[c];
                  else
                     key=kbFunNormal[c];
                 }
               break;
       // ^Q
       case 1: key=kbFunCtrlQNorm[c];
               break;
       // ^K
       case 2: if (S & kbShiftFlg)
                  key=kbFunCtrlKShift[c];
               else
                  key=kbFunCtrlKNorm[c];
               break;
      }

    keyState = 0;
    if ( key != 0 )
      {
       if (key>=254)
         {
          keyState=256-key;
          clearEvent(event);
         }
       else
	 {
	  event.what = evCommand;
	  event.message.command = key+cmbBaseNumber;
	 }
      }
   }
}

/****************************************************************************

   Function: Boolean cursorVisible()

   Type: TCEditor member.

   Objetive: Make visible the cursor.

   From Borland's TV 1.03.

****************************************************************************/

Boolean TCEditor::cursorVisible()
{
 return ((curPos.y >= delta.y) && (curPos.y < delta.y + size.y)) ? True : False;
}


/****************************************************************************

   Function: void deleteRange( uint32 startPtr,uint32 endPtr,
			       Boolean delSelect )

   Type: TCEditor member.

   Objetive: Delete the piece of text from startPtr to endPtr or the selected
   text.

   Parameters:
   startPtr endPtr: Range to delete.
   delSelect: If True and there is a selection deletes the selected text.

   This function is only for compatibility

   by SET.

****************************************************************************/

void TCEditor::deleteRange( uint32 startPtr,
			    uint32 endPtr,
			    Boolean delSelect
			 )
{
 if ( hasSelection() && delSelect )
    deleteSelect();
 else
    deleteRange(buffer+startPtr,buffer+endPtr);
}


/****************************************************************************

   Function: void deleteSelect()

   Type: TCEditor member.

   Objetive: Delete the selected text.

   by SET.

****************************************************************************/

void TCEditor::deleteSelect()
{
 if (hasSelection())
    deleteRange(buffer+selStart,buffer+selEnd);
}


/****************************************************************************

   Function: void doneBuffer()

   Type: TCEditor member.

   Objetive: Delete the editor buffer.

   From Borland's TV 1.03.

****************************************************************************/

void TCEditor::doneBuffer()
{
 delete buffer;
}

/****************************************************************************

   Function: void doSearchReplace()

   Type: TCEditor member.

   Objetive: Make a Search or Replace in the text.

   From Borland's TV 1.03.

****************************************************************************/

void TCEditor::doSearchReplace()
{
 int i;
 do
  {
   i = cmCancel;
   if ( !search(findStr, editorFlags) )
     {
      if ( (editorFlags & (efReplaceAll | efDoReplace)) !=
	   (efReplaceAll | efDoReplace) )
	 editorDialog( edSearchFailed );
     }
   else
      if ( (editorFlags & efDoReplace) != 0 )
	{
	 i = cmYes;
	 if ( (editorFlags & efPromptOnReplace) != 0 )
	   {
	    TPoint c = makeGlobal( cursor );
	    i = editorDialog( edReplacePrompt, &c );
	   }
	 if ( i == cmYes )
	   {
	    lock();
            lockUndo();
            deleteRange(buffer+selStartF,buffer+selEndF);
            int l=strlen(replaceStr);
	    insertText( replaceStr, l, False);
	    trackCursor(False);
            StartOfSearch=selStartF+l;
            unlockUndo();
	    unlock();
	   }
         else
            StartOfSearch=selEndF;
	}
  }
 while( i != cmCancel && (editorFlags & efReplaceAll) != 0 );
}

/****************************************************************************

   Function: int TestPropagation(uint32 OldAttr,uin16 NewAttr,
				 char *proxLine, uint32 proxLineNum)

   Type: TCEditor member.

   Objetive: Check if the changes made in a line affects the next lines and
   if is the case update all the affected lines.
     This function updates the syntax highlight flags, for example if you
   start a comment in a line this produce a propagation.

   Parameters:
   OldAttr: Old syntax flags for this line.
   NewAttr: New syntax flags for this line.
   proxLine: a pointer to the next line.
   proxLineNum: the number of the next line.

   by SET.

****************************************************************************/

int TCEditor::TestPropagation(uint32 OldAttr,uint16 NewAttr,
			      char *proxLine, uint32 proxLineNum)
{
 uint16 PrevAttr;

 if ((OldAttr & FilterProp) != ((unsigned)NewAttr & FilterProp))
   { // The changes afects the rest of the file
    PrevAttr=NewAttr;
    do
     {
      OldAttr=lenLines.getAttr(proxLineNum);
      proxLine+=LineMeassure(proxLine,proxLine+lenLines[proxLineNum],PrevAttr);
      lenLines.setAttr(proxLineNum,PrevAttr);
      proxLineNum++;
     }
    while (OldAttr!=(unsigned)PrevAttr && (unsigned)(proxLine-buffer)<bufLen);
    return 1;
   }
 return 0;
}

/****************************************************************************

   Function: void doUpdate()
	     
   Type: TCEditor member.

   Objetive: Update the screen according to updateFlags.

   by SET.

   ToDo:
   1st step) Avoid a constant LineMeassure, call it only when a special key
   is pressed or when some special thing is deleted.
   2nd step) ? Never call to LineMeassure, keep track of the syntax at
   cursor position.

****************************************************************************/

void TCEditor::doUpdate()
{
 if ( updateFlags != 0 ) // Only if needed
   {
    // moves the hardware cursor
    setCursor(curPos.x - delta.x, curPos.y - delta.y);

    // Repair the highligthed position
    if (IsHLCOn && (updateFlags & (ufLine | ufFound | ufStatus | ufHLChar)))
      {
       int y=YHLC-delta.y;
       int x=XHLC-delta.x;
       if (x>=0 && x<size.x && y>=0 && y<size.y)
          setAttrOfCoor(x,y,OldHLAttr);
       y=YHLCo-delta.y;
       x=XHLCo-delta.x;
       if (x>=0 && x<size.x && y>=0 && y<size.y)
          setAttrOfCoor(x,y,OldHLAttro);
       IsHLCOn=False;
      }

    unsigned selAuxE=0,selAuxS=0;
    Boolean  oldSelHided=selHided;

    // Used for a temporal select when the search was OK.
    if (updateFlags & ufFound)
      { // Put the selection of the found
       selAuxE=selEnd;
       selAuxS=selStart;
       selEnd=selEndF;
       selStart=selStartF;
       selHided=False;
       IsFoundOn=True;
      }
    else
      {
       if (IsFoundOn)
         { // Put away the fake select
          updateFlags|=ufView;
          IsFoundOn=False;
         }
      }

    if (IsStatusLineOn && !(updateFlags & ufView))
      { // Repair the damage of the status line
       int y=delta.y,i=size.y-1;
       unsigned p=drawPtr;

       for (;i;--i)
           p+=lenLines[y++];
       drawLines( y, 1, p );
       IsStatusLineOn=False;
      }

    if ( (updateFlags & ufView) != 0 )
      {
       if (IslineInEdition && (updateFlags & ufLine))
         { // When we type in the last column the editor forces a full draw and we must
           // test for propagation even when isn't an ufLine allone.
          uint16 attr;
          if (curPos.y)
             attr=lenLines.getAttr(curPos.y-1);
          else
             attr=0;
          LineMeassure(bufEdit,inEditPtr+restCharsInLine,attr);
          TestPropagation(attrInEdit,attr,curLinePtr+lenLines[curPos.y],curPos.y+1);
          attrInEdit=attr;
         }
       drawView(); // All the window
      }
    else
       if ( (updateFlags & ufLine) != 0 )
	 {
	  if (IslineInEdition)
	    { // The following is a test and can be optimized a lot
	      uint16 attr;
	      if (curPos.y)
		 attr=lenLines.getAttr(curPos.y-1);
	      else
		 attr=0;
	      LineMeassure(bufEdit,inEditPtr+restCharsInLine,attr);
	      if (TestPropagation(attrInEdit,attr,curLinePtr+lenLines[curPos.y],curPos.y+1))
		{
		 attrInEdit=attr;
		 drawView();
                 updateFlags|=ufView;
		}
	      else
		{
		 attrInEdit=attr;
		 drawLines( curPos.y, 1, (uint32)(curLinePtr-buffer) );
		}
	    }
	  else
	     drawLines( curPos.y, 1, (uint32)(curLinePtr-buffer) ); // only this line
	 }

    // For the find & replace
    if (updateFlags & ufFound)
      { // Let OK the select
       selEnd=selAuxE;
       selStart=selAuxS;
       selHided=oldSelHided;
      }

    if (CrossCursorInCol || CrossCursorInRow)
       updateCrossCur();

    // The status line
    if (updateFlags & ufStatus)
      { // Put it at memorize the situation
       IsStatusLineOn=True;
       writeLine(0, size.y-1, size.x, 1, StatusLine);
      }

    if (updateFlags & ufHLChar)
      {
       int y=YHLC-delta.y;
       int x=XHLC-delta.x;
       char c=getColor(cMPHighL);
       IsHLCOn=True;
       getAttrsOfCol(x,y,y,&OldHLAttr);
       setAttrOfCoor(x,y,c);
       y=YHLCo-delta.y;
       x=XHLCo-delta.x;
       getAttrsOfCol(x,y,y,&OldHLAttro);
       setAttrOfCoor(x,y,c);
      }

    // rest of the things
    if ( hScrollBar != 0 )
       hScrollBar->setParams(delta.x, 0, limit.x - size.x, size.x / 2, 1);
    if ( vScrollBar != 0 )
       vScrollBar->setParams(delta.y, 0, limit.y, size.y - 1, 1); // - size.y cutted
    if ( indicator != 0 )
       indicator->setValue(curPos, modified);
    if ( (state & sfActive) != 0 )
       updateCommands();
    updateFlags = 0;
   }
}

/****************************************************************************

   Function: void updateCrossCur(void)

   Type: TCEditor member.

   Objetive: Update the extended cursor (column, row or cross).

     The basic routine is very simple, the actual routine is a little
   complicated because is optimized to allow some redraws.

   by SET.

****************************************************************************/

void TCEditor::updateCrossCur(void)
{
 int i;
 int xAnt=CrossCursorCol;
 int xAct=curPos.x-delta.x;
 int yAnt=CrossCursorRow;
 int yAct=curPos.y-delta.y;
 int updateCol=1;
 int updateRow=1;
 char color=getColor(cCrossCur);

 // Erase the old Col-cursor
 if (CrossCursorInCol)
   {
    if (updateFlags & ufView)
       // If the editor was redrawed there is no need to do this
       CrossCursorY2=size.y;
    else
      {
       if (CrossCurInCacheC)
         { // Only if we have the info in the cache
          if (xAnt!=xAct)
            { // If the col was changed make a full erase
             if (updateFlags & ufLine)
               {
                // if the line was redrawed don't touch it
                for (i=0; i<CrossCursorY2; i++)
                    if (i!=yAct)
                       setAttrOfCoor(CrossCursorCol,i,CrossCursorBuf[i]);
               }
             else
               {
                // full column erase
                for (i=0; i<CrossCursorY2; i++)
                    setAttrOfCoor(CrossCursorCol,i,CrossCursorBuf[i]);
               }
            }
          else
            {
             // erase only the last row, but only if the line is unmodified
             if (!(updateFlags & ufLine))
                setAttrOfCoor(xAct,yAct,CrossCursorBuf[yAct]);
             updateCol=0;
            }
         }
      }
   }

 // Erase the old Row-cursor
 if (CrossCursorInRow)
   {
    if (updateFlags & (ufView | ufLine))
       // If the editor was redrawed there is no need to do this
       CrossCursorX2=size.x;
    else
      {
       if (CrossCurInCacheR)
         { // Only if we have the info in the cache
          if (yAnt!=yAct)
            { // If the row was changed make a full erase
             for (i=0; i<CrossCursorX2; i++)
                 setAttrOfCoor(i,CrossCursorRow,CrossCursorBufR[i]);
            }
          else
            {
             // erase only the last col, but only if the value changed
             if (xAct!=xAnt)
                setAttrOfCoor(xAct,yAct,CrossCursorBufR[xAct]);
             updateRow=0;
            }
         }
      }
   }

 CrossCursorCol=xAct;
 CrossCursorRow=yAct;

 // Draw the new Col-cursor
 if (CrossCursorInCol)
   {
    int i;

    if (updateCol)
      {
       // If a full erase was done make a full draw
       // First try to copy all in the cache
       if (getAttrsOfCol(CrossCursorCol,0,CrossCursorY2,CrossCursorBuf))
          CrossCurInCacheC=False;
       else
         {
          // If all is in the cache draw the col, but not where the cursor is
          for (i=0; i<CrossCursorY2; i++)
              if (i!=CrossCursorRow)
                 setAttrOfCoor(CrossCursorCol,i,color);
          CrossCurInCacheC=True;
         }
      }
    else
      {
       // If only one character was erased draw only one
       if (getAttrsOfCol(CrossCursorCol,yAnt,yAnt,&CrossCursorBuf[yAnt]))
          CrossCurInCacheC=False;
       else
         {
          if (yAnt!=yAct)
             setAttrOfCoor(CrossCursorCol,yAnt,color);
          CrossCurInCacheC=True;
         }
      }
   }

 // Draw the new Row-cursor
 if (CrossCursorInRow)
   {
    int i;

    if (updateRow)
      {
       if (getAttrsOfRow(0,CrossCursorX2,CrossCursorRow,CrossCursorBufR))
          CrossCurInCacheR=False;
       else
         {
          for (i=0; i<CrossCursorX2; i++)
              if (i!=CrossCursorCol)
                 setAttrOfCoor(i,CrossCursorRow,color);
          CrossCurInCacheR=True;
         }
      }
    else
      {
       if (getAttrsOfRow(xAnt,xAnt,CrossCursorRow,&CrossCursorBufR[xAnt]))
          CrossCurInCacheR=False;
       else
         {
          setAttrOfCoor(xAnt,CrossCursorRow,color);
          CrossCurInCacheR=True;
         }
      }
   }
}

/****************************************************************************

   Function: void draw()

   Type: TCEditor member.

   Objetive: Update the content of the window (the text, not the rest).

   by SET.

****************************************************************************/

void TCEditor::draw()
{
 AdjustDrawPtr();
 drawLines( drawLine, size.y, drawPtr );
}

/****************************************************************************

   Function: void AdjustDrawPtr(void)

   Type: TCEditor member.

   Objetive: Update the current pointer for drawing.
     The drawPtr pointer keeps track of the position that correspond to the
   drawLine variable, this variable is the first line drawed by drawLine by
   draw. This value is adjusted each time the delta.Y is modified in the
   window. The calculus is made based on the assumption that the actual
   values: drawLine and drawPtr are OK, some routines can modify the buffer
   invalidating this pair of values, under such situations is necesary to
   make these two values coherents, a method is make the both 0, but then
   this routine must spend more time to recalculate the actual values,
   another way is move these values to a point that will not be modified in
   the routine. To see an example see UnIndentBlock.

   by SET.

****************************************************************************/

void TCEditor::AdjustDrawPtr(void)
{
 unsigned deltaY=delta.y;

 if ( drawLine!=deltaY )
   {
    // Adjust the pointer drawPtr
    if (drawLine>deltaY)
       for (;drawLine>deltaY; drawLine--)
	   drawPtr-=lenLines[drawLine-1];
    else
       for (;drawLine<deltaY; drawLine++)
	   drawPtr+=lenLines[drawLine];
   }
}


/****************************************************************************

   Function: uint32 LenWithoutCRLF(uint32 y, char *cl)

   Type: TCEditor member.

   Objetive: Compute the length of a line, but excluding the '\r','\n' at the
   end of the line.

   by SET.

****************************************************************************/

uint32 TCEditor::LenWithoutCRLF(uint32 y, char *cl)
{
 unsigned len=lenLines[y];
 //MyAssert(len==1);
 /* Remove at first LF */
 if (len>0 && cl[len-1]=='\n') len--;
 /* and now CR on DOS-files */
 if (len>0 && cl[len-1]=='\r') len--;
 return len;
}

/****************************************************************************

   Function: void drawLines( int y, int count, uint32 linePtr )
	     
   Type: TCEditor member.

   Objetive: Draw some lines in the screen.

   Parameters:
   y: pos in the file (not the window)
   count: number of lines to draw
   linePtr: offset of the start of the line in the buffer

   by SET.

   ToDo:
   If necesary a best patch for the draw of the line in edition.

****************************************************************************/

void TCEditor::drawLines( int y, int count, uint32 linePtr )
{
 uint16 color = getColor(0x0201);
 unsigned yInFile=y;
 Boolean FirstEmpty=True;
 y-=delta.y;
 unsigned width=delta.x+size.x;
 int IsPostRectOn=0;   // Indicates that there is no need to paint the rect
 char *bc;             // Alias to access to the buffer with chars
 int OffXr1=0,OffXr2=0,Off;
 char ColRect=0;

#ifdef CACHED_COLORS
 if (!colorsCached)
   {
    CacheColors();
    colorsCached=1;
   }
#endif

 // Set IsPostRectOn only if really needed
 if (hasRectSel())
   {
    if (Xr1<(int)width && Xr2>=delta.x && Yr1<delta.y+size.y && Yr2>=delta.y)
      {
       IsPostRectOn=1;
       OffXr1=(Xr1<<1)+1;
       OffXr2=((min(Xr2-1,width))<<1)+1;
       ColRect=getColor(cRectSel);
      }
   }

 // temporal buffer, ever 1 more than the width to avoid problems
 ushort *b=(ushort *)alloca((width+tabSize+16+1)<<1);
 //ushort b[maxLineLenBuff]; Old fix-length version.
 if (b==NULL) abort();
 bc=(char *)b;

 while ( count-- > 0 )
    {
     if (yInFile<=totalLines)
       {
	if (IslineInEdition && yInFile==(unsigned)curPos.y)
	  {
	   char *bb=buffer;
	   unsigned s=selStart,e=selEnd;
	   unsigned bs=bufLen;
	   bufLen=delta.x+size.x;
	   selStart=selLineStart;
	   selEnd=selLineEnd;
	   buffer=bufEdit;
           (this->*formatLinePtr)( b, 0, width, color,(unsigned)(inEditPtr+restCharsInLine-bufEdit),attrInEdit,yInFile);
	   buffer=bb;
	   selEnd=e;
	   selStart=s;
	   bufLen=bs;
	  }
	else
	   (this->*formatLinePtr)( b, linePtr, width, color, LenWithoutCRLF(yInFile,buffer+linePtr), lenLines.getAttr(yInFile),yInFile);

        if (IsPostRectOn)
          {
           if (yInFile>=(unsigned)Yr1 && yInFile<=(unsigned)Yr2)
              for (Off=OffXr1; Off<=OffXr2; Off+=2)
                  bc[Off]=ColRect;
          }

#ifdef TEST_SPLINES
       {
        int i,off,j;
        if (SpecialLines)
           for (i=0; SpecialLines[i]!=splEndOfList; i++)
               if (SpecialLines[i]==yInFile)
                  for (off=delta.x, j=size.x; j; off++,j--)
                      bc[off*2+1]=0xF0;
       }
#endif

        writeLine(0,y, size.x, 1, &b[delta.x]);
	// Adjust the pointer linePtr
	linePtr = linePtr+lenLines[yInFile++];
       }
     else
       { // Empty lines
	if (FirstEmpty)
	  { // If is the first make the empty line
	   FirstEmpty=False;
	   ushort Val=((color & 0xff)<<8) | 0x20;
	   for (int i=size.x; i;)
	       b[--i]=Val;
	  }
        writeLine(0,y, size.x, 1, b);
        yInFile++;
       }
     y++;
    }
}


/****************************************************************************

   Function: void setStatusLine(char *s)

   Type: TCEditor member.

   Objetive: Put text in the status line.

   Parameter:
   char *s: text to put.

   by SET.

****************************************************************************/

void TCEditor::setStatusLine(char *s)
{
 int l=strlen(s);
 char color=getColor(cStatusLi);

 if (l>=setMaxScreenX)
    l=setMaxScreenX-1;

 int fill=setMaxScreenX-1-l;
 char *b=StatusLine;

 while (l--)
   {
    *(b++)=*(s++);
    *(b++)=color;
   }

 while (fill--)
   {
    *(b++)=' ';
    *(b++)=color;
   }

 update(ufStatus);
}


static unsigned PipeOrigin;
static char    *PipeBuf;
static unsigned PipeBufLen;

int PipeTCEditor(unsigned PosRel)
{
 if (PosRel+PipeOrigin<PipeBufLen)
    return PipeBuf[PosRel+PipeOrigin];
 return -1;
}

/****************************************************************************

   Function: void find()

   Type: TCEditor member.

   Objetive: Make the dialog and search in the text.

   by SET.

****************************************************************************/

void TCEditor::find()
{
 char *Word;

 if ((Word=WordUnderCursor(80))!=NULL)
   {
    strcpy(findStr,Word);
    delete Word;
   }

 TFindCDialogRec findRec( findStr, editorFlags, SearchInSel, FromWhere );

 if ( editorDialog( edFind, &findRec ) != cmCancel )
   {
    strcpy( findStr, findRec.find );
    editorFlags = findRec.options & ~efDoReplace;
    SearchInSel = findRec.in_sel;
    FromWhere = findRec.from;
    if (FromWhere)
       StartOfSearch=0; // All
    else
       StartOfSearch=(unsigned)(ColToPointer()-buffer);
    doSearchReplace();
   }
}

/****************************************************************************

   Function: char *WordUnderCursor(uint32 maxLength)
	     
   Type: TCEditor member.

   Objetive: Search the word under the cursor position.

   Parameter:                             
   maxLength: The maximun allowed length for the word.

   Return: A pointer to the string (a new allocated one) or NULL if the 
   cursor isn't over a word.

   Added: Support for the Pipe.

   by SET.

****************************************************************************/

char *TCEditor::WordUnderCursor(uint32 maxLength)
{
 char *word,*aux;
 char *word_start,*word_end,*i;
 unsigned l;

 if (IslineInEdition)
    MakeEfectiveLineInEdition();

 char *s=ColToPointer();
 char *end=buffer+bufLen;

 // Set-Up the pipe
 PipeOrigin=(unsigned)(s-buffer);
 PipeBuf=buffer;
 PipeBufLen=bufLen;

 if (!isWordChar(*s))
    return NULL;

 word_start = s;
 while (--word_start>buffer && isWordChar(*word_start));
 if (word_start!=buffer || !isWordChar(*word_start))
    word_start++;

 word_end = s;
 while (++word_end<end && isWordChar(*word_end));
 if (word_end!=end || !isWordChar(*word_end))
    word_end--;

 // Adjust the pipe
 PipeOrigin=(unsigned)(word_start-buffer);

 l=(unsigned)(word_end-word_start+2);
 if (l>maxLength)
    return NULL;
 word = new char[l];

 for (i=word_start,aux=word; i<=word_end; i++)
     *aux++ = *i;
 *aux=0;

 return word;
}

/****************************************************************************

   Function: void SelWordUnderCursor(void)

   Type: TCEditor member.

   Objetive: Select the word under cursor.

   by SET.

****************************************************************************/

void TCEditor::SelWordUnderCursor(void)
{
 char *p=ColToPointer();
 char *end=buffer+bufLen;

 if (isWordChar(*p))
   {
    // Walk backward to the start of a word
    for (;p>buffer && isWordChar(*p); --p);
    if (p!=buffer) p++;
   }
 else
   {
    // If isn't in a word walk forward
    for (;p<end && !isWordChar(*p); ++p);
    if (!isWordChar(*p))
       return;
   }
 selStartOffSet=selStart=(uint32)(p-buffer);
 // Now forward to the end
 for (;p<end && isWordChar(*p); ++p);
 selEnd=(uint32)(p-buffer);
}

/****************************************************************************

   Function: void MoveToMouse( TPoint m, uchar selMode )

   Type: TCEditor member.

   Objetive: Move the cursor to the position pointed by the mouse updating
   the selection if necesary.
     Handle the double click to select the word under cursor.

   Parameter:                             
   TPoint m: The point where the mouse is.
   uchar selMode: The flags for the selection mode.

   by SET.

****************************************************************************/

void TCEditor::MoveToMouse( TPoint m, uchar selMode )
{
 TPoint mouse = makeLocal( m );
 mouse.x = max(0, min(mouse.x, size.x - 1));
 mouse.y = max(0, min(mouse.y, size.y - 1));

 MoveCursorTo(mouse.x+delta.x,mouse.y+delta.y);
 if (selMode & smExtend)
   { // Extends the selection
    unsigned selAux=(unsigned)(ColToPointer()-buffer); // To where?
    if (selAux>selStartOffSet)
      {
       selEnd=selAux;
       selStart=selStartOffSet;
      }
    else
      {
       selEnd=selStartOffSet;
       selStart=selAux;
      }
   }
 else
   { // Starts a selection
    if (selMode & smDouble)
      { // Select the word under cursor or the nearest
       SelWordUnderCursor();
      }
    else
      {
       int dif;
       selStart=(uint32)(ColToPointer(dif)-buffer);
       if (dif>0)
          selStart--;
       selEnd=selStartOffSet=selStart;
      }
    selHided=False;
   }
 update(ufView);
}

/****************************************************************************

   Function: TPalette& getPalette() const
	     
   Type: TCEditor member.

   Objetive: Return the palette for the editor.

   Return: a reference to the palette.

   From Borland's TV 1.03.

****************************************************************************/

TPalette& TCEditor::getPalette() const
{
 static TPalette palette( cpEditor, sizeof( cpEditor )-1 );
 return palette;
}

/****************************************************************************

   Function: void checkScrollBar( const TEvent& event, TScrollBar *p,
				  int& d )
	     
   Type: TCEditor member.

   Objetive: ? Check if the event is a change in the Scroll bars.

   From Borland's TV 1.03.

****************************************************************************/

void TCEditor::checkScrollBar( const TEvent& event,
			      TScrollBar *p,
			      int& d
			    )
{
 if ( (event.message.infoPtr == p) && (p->value != d) )
   {
    d = p->value;
    if (IslineInEdition)
       MakeEfectiveLineInEdition();
    update( ufView );
   }
}

/****************************************************************************

   Function: int IsFirstCharInLine(void)
	     
   Type: TCEditor member.

   Objetive: Check if the cursor is over the first non-blanc char in the
   line.
     Works when a line is in edition and when isn't.

   Return: 0 not OK.

   by SET

****************************************************************************/

int TCEditor::IsFirstCharInLine(void)
{
 if (IslineInEdition)
   {
    char *s=bufEdit;

    for (;*s!='\r' && *s!='\n' && s!=inEditPtr && isspace(*s); s++);
    return s==inEditPtr;
   }
 char *s=curLinePtr;
 uint32 l=LenWithoutCRLF(curPos.y,curLinePtr),x,xpos=curPos.x,i;

 for (x=0,i=0; x<xpos && i<l && isspace(*s); s++,i++)
    { AdvanceWithTab(*s,x); }
 return x==xpos;
}

/****************************************************************************

   Function: int GoFirstCharInLine(void)

   Type: TCEditor member.

   Objetive: Put the cursor on the first non-blank character in the line, if
   exists.

   Return: 0 not OK.

   by SET

****************************************************************************/

int TCEditor::GoFirstCharInLine(void)
{
 char *s;
 uint32 l,x,i;

 if (IslineInEdition)
   {
    s=bufEdit;
    l=(uint32)(inEditPtr-bufEdit+restCharsInLine);
   }
 else
   {
    s=curLinePtr;
    l=LenWithoutCRLF(curPos.y,curLinePtr);
   }

 for (x=0,i=0; i<l && isspace(*s); s++,i++)
    { AdvanceWithTab(*s,x); }
 if (i<l)
   {
    curPos.x=x;
    update(ufUpdate);
    return 1;
   }
 return 0;
}

/****************************************************************************

   Function: void handleEvent( TEvent& event )

   Type: TCEditor member.

   Objetive: Is the main switch/case of the class.

   by SET

   ToDo: Put in separated routines the cases.

****************************************************************************/

void TCEditor::handleEvent( TEvent& event )
{
    TView::handleEvent( event );
    //if (macros) macros->handleEvent(event,this);
    convertEvent( event );
    Boolean centerCursor = (!cursorVisible()) ? True : False;
    uchar selectMode = 0;
    int i; // To be used as iterator in any of the case in the switch
    unsigned char Character;

    // The following if deals with the Shift, I can't get the shift state
    // from the event structure because the code must work even if the
    // event is a command, so I use the actual state of shift.
    if (ForceSelection)
      {
       // Used to reproduce a macro command recorded with selection info.
       selectMode=ForceSelection;
      }
    else
      {
       if (selecting)
         {
          if ((shiftkeys() & kbFlagsShift) != 0)
	     selectMode = smExtend;
          else
	    {
	     selectMode = smEndSel;
	     selecting = False;
	    }
         }
       else
         {
          if ((shiftkeys() & kbFlagsShift) != 0)
	     selectMode = smStartSel;
         }
      }

    switch( event.what )
       {
	// Mouse events, Full Ok Level 1
	case evMouseDown:
	     if (IslineInEdition)
		MakeEfectiveLineInEdition();
	     if ( event.mouse.doubleClick )
		selectMode |= smDouble;
	     do
	       {
		lock();
		if (event.what==evMouseAuto)
		  {
		   TPoint mouse = makeLocal( event.mouse.where );
		   TPoint d = delta;
		   if( mouse.x < 0 )
		       d.x--;
		   if( mouse.x >= size.x )
		       d.x++;
		   if( mouse.y < 0 )
		       d.y--;
		   if( mouse.y >= size.y )
		       d.y++;
		   scrollTo(d.x, d.y);
		  }
		MoveToMouse(event.mouse.where,selectMode);
		//setCurPtr(getMousePtr(event.mouse.where), selectMode);
		selectMode |= smExtend;
		unlock();
	       }
	     while( mouseEvent(event, evMouseMove + evMouseAuto) );
	     break;
        // ***** end of evMouseDown

	// a Keyboard event (a Key without any special function)
	case evKeyDown:
            Character=event.keyDown.charScan.charCode;
	    if ( Character==9 || (  Character>=32 && Character<255 ) )
	      {
	       lock();
               CutIfNotPersistent();
               //addToUndo(undoPutChar,(void *)&Character);
	       if (!IslineInEdition)
		  EditLine();
               if (IslineInEdition)
                 {
	          InsertCharInLine(Character);
                  if (Recording)
                    {
                     if (MacroCount<32)
                        MacroArray[MacroCount++]=0xF000+Character;
                    }
	          update(ufLine);
                 }
               unlock();
	      }
	    else
		return;
	    break;
        // **** end of evKeyDown

        // a Command event
	case evCommand:
	    switch( event.message.command )
	       {
		case cmcFind:
		     if (IslineInEdition)
			MakeEfectiveLineInEdition();
		     find();
		     break;

		case cmcReplace:
		     if (IslineInEdition)
			MakeEfectiveLineInEdition();
		     replace();
		     break;

                // ^L
		case cmcSearchAgain:
		     if (IslineInEdition)
			MakeEfectiveLineInEdition();
                     StartOfSearch=(unsigned)(ColToPointer()-buffer)+1;
		     doSearchReplace();
		     break;

		default:
		    lock();
                    lockUndo();
		    switch( event.message.command )
		       {
			// ^KY or ShiftDel Full Level 2
			case cmcCut:
			     clipCut();
			     break;

			// Full Level 2
			case cmcCopy:
		             clipCopy();
			     break;

			// Full Level 2
			case cmcPaste:
                             if (PersistentBlocks)
                                clipPaste();
                             else
                               {
                                clipReplace();
                                selEnd=selStart;
                               }
			     break;

                        // Alt+Backspace
			case cmcUndo:
			     undo();
			     break;

                        // No key
			case cmcRedo:
			     redo();
			     break;

                        // Ctrl+Del, Full Level 2
			case cmcClear:
			     if (IslineInEdition)
				MakeEfectiveLineInEdition();
			     deleteSelect();
			     break;

                        // ^KC
                        case cmcCopyBlock:
                             if (PersistentBlocks && hasSelection())
                               {
                                if (!selHided)
                                  {
                                   if (IslineInEdition)
				      MakeEfectiveLineInEdition();
                                   char *s;
                                   unsigned l=selEnd-selStart;
                                   s=new char[l];
                                   if (s)
                                     {
                                      memcpy(s,buffer+selStart,l);
                                      insertBuffer(s,0,l,True,True);
                                      delete s;
                                     }
                                  }
                                else
                                  {
                                   selHided=False;
                                   update(ufView);
                                  }
                               }
                             break;

			// Full Ok level 2 + selExtend
			case cmcCharLeft:
			     if (curPos.x>0)
			       {
                                CheckForShiftSelection();
                                addToUndo(undoInMov);
				curPos.x--;
				if (IslineInEdition)
				  {
				   if (*inEditPtr==9)
				     {
				      if (curPos.x<LineWidth(bufEdit,inEditPtr))
					{
					 inEditPtr--;
					 restCharsInLine++;
					}
				     }
				   else
				     {
				      inEditPtr--;
				      restCharsInLine++;
				     }
                                   ClearSelIfNonPers();
				  }
				else // Line in edition
				  {
				   if (selectMode==smExtend)
				     {
				      UpdateSelecting();
				      update(ufLine);
				     }
                                   else
                                      ClearSelIfNonPers();
				  }
				update(ufUpdate);
			       }
			     break;

			// Full Ok level 2 + selExtend
			case cmcCharRight:
			     if (curPos.x<MaxLineLen)
                               {
                                CheckForShiftSelection();
			        if (IslineInEdition)
			          {
                                   addToUndo(undoInMov);
				   if (*inEditPtr)
				     {
				      curPos.x++;
				      if (*inEditPtr==9)
				        {
				         if (IsATabPos(curPos.x))
					   {
					    inEditPtr++;
					    restCharsInLine--;
					   }
				        }
				      else
				        {
				         inEditPtr++;
				         restCharsInLine--;
				        }
				      update(ufUpdate);
				     }
				   else
				     {
				      InsertCharInLine(32);
				      restCharsInLine=0;
				      update(ufLine);
				     }
                                   ClearSelIfNonPers();
			          }
			        else // IslineInEdition
			          {
                                   addToUndo(undoInMov);
				   curPos.x++;
				   if (selectMode==smExtend)
				     {
				      UpdateSelecting();
				      update(ufLine);
				     }
				   else
                                     {
				      update(ufUpdate);
                                      ClearSelIfNonPers();
                                     }
			          }
                               }
			     break;

			// Full OK Level 2 + selExtend
			case cmcWordLeft:
                             if (curPos.y>0 || curPos.x>0)
                               {
                                CheckForShiftSelection();
			        if (IslineInEdition) // This can be optimized
				   MakeEfectiveLineInEdition();
                                addToUndo(undoInMov);
			        prevWord();
			        if (selectMode==smExtend)
			          {
				   UpdateSelecting();
				   update(ufView);
			          }
			        else
                                  {
				   update(ufUpdate);
                                   ClearSelIfNonPers();
                                  }
                               }
			     break;

			// Full OK Level 2 + selExtend
			case cmcWordRight:
                             CheckForShiftSelection();
			     if (IslineInEdition) // This can be optimized
				MakeEfectiveLineInEdition();
                             addToUndo(undoInMov);
			     nextWord();
			     if (selectMode==smExtend)
			       {
				UpdateSelecting();
				update(ufView);
			       }
			     else
                               {
				update(ufUpdate);
                                ClearSelIfNonPers();
                               }
			     break;

			// Full OK Level 2 + selExtend
			case cmcLineStart:
                             CheckForShiftSelection();
                             addToUndo(undoInMov);
			     if (IslineInEdition)
			       {
				restCharsInLine+=(int)(inEditPtr-bufEdit);
				inEditPtr=bufEdit;
			       }
			     curPos.x=0;
			     if (selectMode==smExtend)
			       {
				UpdateSelecting();
				update(ufLine);
			       }
			     else
                               {
				update(ufUpdate);
                                ClearSelIfNonPers();
                               }
			     break;

			// Full OK Level 2 + selExtend
			case cmcLineEnd:
			    {
                             CheckForShiftSelection();
                             addToUndo(undoInMov);
			     int len=0;
			     i=0;
			     if (IslineInEdition)
			       {
				// Calculate the "visible" length of the line
                                char *auxPos=bufEdit;
                                char *lastUsedPos=auxPos;
                                int  lastUsedX=0;
				while (*auxPos)
				   {
				    AdvanceWithTab(*auxPos,len);
                                    if (!isspace(*auxPos))
                                      {
                                       lastUsedPos=auxPos;
                                       lastUsedX=len;
                                      }
				    auxPos++;
				   }
				restCharsInLine=0;
                                inEditPtr= ++lastUsedPos;
                                *lastUsedPos=0;
                                len=lastUsedX;
			       }
			     else
			       {
				// Calculate the "visible" length of the line
                                int c=LenWithoutCRLF(curPos.y,curLinePtr);
				while (c--)
				   {
				    AdvanceWithTab(curLinePtr[i],len);
                                    i++;
                                   }
			       }
			     curPos.x=len;
			     if (selectMode==smExtend)
			       {
				UpdateSelecting();
				update(ufLine);
			       }
			     else
                               {
				update(ufUpdate);
                                ClearSelIfNonPers();
                               }
			    }
			     break;

			// Full OK level 2 + selExtend
			case cmcLineUp:
			    if (curPos.y>0)
			      {
                               CheckForShiftSelection();
                               addToUndo(undoInMov);
			       if (IslineInEdition)
				  MakeEfectiveLineInEdition();
			       curLinePtr-=lenLines[--curPos.y];
			       if (selectMode==smExtend)
				 {
				  UpdateSelecting();
				  update(ufView);
				 }
                               else
                                 {
			          update(ufUpdate);
                                  ClearSelIfNonPers();
                                 }
			      }
			    break;

			// Full OK level 2 + selExtend
			case cmcLineDown:
			    if ((unsigned)curPos.y<totalLines)
			      {
                               CheckForShiftSelection();
                               addToUndo(undoInMov);
			       if (IslineInEdition)
				  MakeEfectiveLineInEdition();
			       curLinePtr+=lenLines[curPos.y++];
			       if (selectMode==smExtend)
				 {
				  UpdateSelecting();
				  update(ufView);
				 }
			       else
                                 {
				  update(ufUpdate);
                                  ClearSelIfNonPers();
                                 }
			      }
			    break;

			// Full Ok level 2 (Pg Up) + selExtend
			case cmcPageUp:
                             CheckForShiftSelection();
                             addToUndo(undoInMov);
			     MoveLinesUp(size.y-1);
                             delta.y=max(delta.y-(size.y-1),0);
			     update(ufView);
			     if (selectMode==smExtend)
				UpdateSelecting();
                             else
                                ClearSelIfNonPers();
			     break;

			// Full Ok level 1 (Pg Down) + selExtend
			case cmcPageDown:
                             CheckForShiftSelection();
                             addToUndo(undoInMov);
			     MoveLinesDown(size.y-1);
                             delta.y=min(delta.y+size.y-1,limit.y);
                             update(ufView);
			     if (selectMode==smExtend)
				UpdateSelecting();
                             else
                                ClearSelIfNonPers();
			     break;

			// Full Ok level 2 (^Pg Up) + selExtend
			case cmcTextStart:
                             CheckForShiftSelection();
                             addToUndo(undoInMov);
			     if (IslineInEdition)
			        MakeEfectiveLineInEdition();
			     curPos.x=0;
			     curPos.y=0;
			     curLinePtr=buffer;
			     if (selectMode==smExtend)
			       {
			        UpdateSelecting();
			        update(ufView);
			       }
			     else
                               {
			        update(ufUpdate);
                                ClearSelIfNonPers();
                               }
			     break;

			// Full Ok level 2 (^Pg Down) + selExtend
			case cmcTextEnd:
			   {
                            CheckForShiftSelection();
                            addToUndo(undoInMov);
			    if (IslineInEdition)
			       MakeEfectiveLineInEdition();
                            MoveLinesDown(totalLines-curPos.y);
                            curPos.x=LenWithoutCRLF(curPos.y,curLinePtr);
			    if (selectMode==smExtend)
			      {
			       UpdateSelecting();
			       update(ufView);
			      }
			    else
                              {
			       update(ufUpdate);
                               ClearSelIfNonPers();
                              }
			   }
			    break;

			// Full OK level 2
			case cmcNewLine:
			     newLine();
			     break;

			// Full Ok level 2 (Backspace)
			case cmcBackSpace:
			     BackSpace();
			     break;


			// Full Ok level 2 (Delete)
			case cmcDelChar:
                             if (!PersistentBlocks && hasSelection())
                               {
                                clipCut();
                                break;
                               }
			     if (IslineInEdition && restCharsInLine)
			       { // easy
                                addToUndo(undoDelCharDel,inEditPtr);
                                int wasATab=*inEditPtr=='\t';
				memcpy(inEditPtr,inEditPtr+1,restCharsInLine);
                                if (wasATab)
                                   RecalculateXofLineInEdit();
				restCharsInLine--;
				modified=True;
				update(ufLine);

				unsigned PosOfIns=(unsigned)(inEditPtr-bufEdit);
                                AdjustLineSel(PosOfIns,-1,False,False);

				// Update the markers
				for (i=0; i<10; i++)
				   {
				    int Pos=MarkersInLine[i];
				    if (Pos>=0 && (unsigned)Pos>PosOfIns)
				       MarkersInLine[i]--;
				   }
			       }
			     else
                               {
                                // Could be optimized
                                if (IslineInEdition)
                                   MakeEfectiveLineInEdition();

                                // 2 cases: 1) in the line 2) outside
				int x=LineWidth();
				if (x>curPos.x)
				  { // OK in the line
				   EditLine();
                                   if (!IslineInEdition)
                                      break;
                                   addToUndo(undoDelCharDel,inEditPtr);
                                   int wasATab=*inEditPtr=='\t';
				   memcpy(inEditPtr,inEditPtr+1,restCharsInLine);
                                   if (wasATab)
                                      RecalculateXofLineInEdit();
				   restCharsInLine--;
				   modified=True;
				   update(ufLine);
				   unsigned PosOfIns=(unsigned)(inEditPtr-bufEdit);
                                   AdjustLineSel(PosOfIns,-1,False,False);
				   // Update the markers
				   for (i=0; i<10; i++)
				      {
				       int Pos=MarkersInLine[i];
				       if (Pos>=0 && (unsigned)Pos>PosOfIns)
					  MarkersInLine[i]--;
				      }
				  }
				else
				  { // No!!!
				   if ((unsigned)curPos.y<totalLines)
				     {
				      // Expand the line
				      int ToInsert=curPos.x-x;
				      //curPos.x=x;
				      // delete the CR-LF
                  char *tmp = curLinePtr+lenLines[curPos.y]-1;
                  if (tmp > buffer && *(tmp-1) == '\r') tmp--;
				      deleteRange(tmp,curLinePtr+lenLines[curPos.y]);
				      if (ToInsert)
					 insertSpaces(ToInsert,x);
				      // To clean extra spaces if exist
				      EditLine();
				     }
				  }
                               }
			     break;

			// Full Ok level 2 (^T)
			case cmcDelWord:
			     {
                              ClearSelIfNonPers();
			      if (IslineInEdition)
				{
				 if (restCharsInLine==0) // If is the end of line
				    MakeEfectiveLineInEdition();
				 else
				   {
				    char *p=inEditPtr;
				    if (!isWordChar(*p))
				       while ( *p &&  !isWordChar(*p) ) p++;
				    else
				       while ( *p &&  isWordChar(*p) ) p++;
				    //while ( *p && !isWordChar(*p)) p++;
                                    while ( *p && isspace(*p)) p++;
				    restCharsInLine-=(int)(p-inEditPtr);
                                    deleteRangeLineInEdition(inEditPtr,p,-1);
				    break;
				   }
				}
                              int dif;
			      char *s=ColToPointer(dif);
                              addToUndo(undoPreDelete);
			      deleteRange(s,s+nextCWord());
                              if (dif<0)
                                 insertSpaces(-dif,curPos.x);
			     }
			    break;

			// ^BackSpace, Full Ok level 2
			case cmcDelPrevWord:
			    {
                             ClearSelIfNonPers();
			     if (IslineInEdition)
				MakeEfectiveLineInEdition();
			     char *s=ColToPointer();
			     deleteRange(s+prevWord(False),s);
			    }
			     break;

			// Full Ok level 2 (^QH)
			case cmcDelStart:
                             ClearSelIfNonPers();
			     if (IslineInEdition)
                                deleteRangeLineInEdition(bufEdit,inEditPtr,0);
			     else
			        deleteRange(curLinePtr,ColToPointer());
			     break;

			// Full Ok level 2 (^QY)
			case cmcDelEnd:
                             ClearSelIfNonPers();
			     if (IslineInEdition)
			       {
                                deleteRangeLineInEdition(inEditPtr,inEditPtr+restCharsInLine,-1);
				restCharsInLine=0;
			       }
			     else
			       {
				char *s=ColToPointer();
				if (*s!='\r' && *s!='\n')
				   deleteRange(s,curLinePtr+LenWithoutCRLF(curPos.y,curLinePtr));
			       }
			     break;

			// Full Ok level 2 (^Y)
			case cmcDelLine:
                             ClearSelIfNonPers();
			     if (IslineInEdition)
				MakeEfectiveLineInEdition();
                             if ((uint32)curPos.y!=totalLines)
			        deleteRange(curLinePtr,curLinePtr+lenLines[curPos.y]);
                             else
                                deleteRange(curLinePtr,curLinePtr+LenWithoutCRLF(curPos.y,curLinePtr));
			     break;

			// ^KB, OK Level 2
			case cmcStartSelect:
                             addToUndo(undoCutInMov,NULL);
			     if (IslineInEdition)
			       {
                                uint32 posL=(uint32)(curLinePtr-buffer);
				selLineStart=(uint32)(inEditPtr-bufEdit);
				selNewStart=posL+selLineStart;
                                selStart=posL;
			       }
			     else
			        selStart=(uint32)(ColToPointer()-buffer);
			     selHided=False;
			     update(ufView);
			     break;

			// ^KK, OK Level 2
			case cmcEndSelect:
			     if (IslineInEdition)
			       {
                                uint32 posL=(uint32)(curLinePtr-buffer);
				selLineEnd=(uint32)(inEditPtr-bufEdit);
				selNewEnd=posL+selLineEnd;
                                selEnd=posL;
			       }
			     else
			        selEnd=(uint32)(ColToPointer()-buffer);
			     selHided=False;
			     update(ufView);
                             addToUndo(undoCutInMov,NULL);
			     break;

			// ^KH Full Ok Level 2
			case cmcHideSelect:
                             addToUndo(undoCutInMov,NULL);
			     hideSelect();
			     break;

			// New ^Home Full Ok Level 2 + selExtend
			case cmcFirstLineInScreen:
                             CheckForShiftSelection();
                             addToUndo(undoInMov);
			     MoveLinesUp(curPos.y-delta.y);
			     if (selectMode==smExtend)
			       {
				UpdateSelecting();
				update(ufView);
			       }
                             else
                               ClearSelIfNonPers();
			     break;

			// New ^End Full Ok Level 2 + selExtend
			case cmcLastLineInScreen:
                             CheckForShiftSelection();
                             addToUndo(undoInMov);
			     MoveLinesDown(delta.y+size.y-curPos.y-1);
			     if (selectMode==smExtend)
			       {
				UpdateSelecting();
				update(ufView);
			       }
                             else
                               ClearSelIfNonPers();
			     break;

			// ^O
			case cmcIndentMode:
			     autoIndent = (!autoIndent) ? True : False;
			     break;

			// ^V
			case cmcInsMode:
			     toggleInsMode(True);
			     break;

			// ^KI Full Ok level 2
			case cmcIndentBlkOne:
			     IndentBlock(1,' ');
			     break;

			// ^KU Full Ok level 2
			case cmcUnIndentBlkOne:
			     UnIndentBlock(1);
			     break;

			// ^KTab Full Ok level 2
			case cmcIndentBlk:
			     if (UseTabs)
				IndentBlock(1,'\t');
			     else
				IndentBlock(0,0);
			     break;

			// ^KShiftTab Full Ok level 2
			case cmcUnIndentBlk:
			     if (UseTabs)
				UnIndentBlock(1);
			     else
				UnIndentBlock(0);
			     break;

                        // ^ShiftIns Full Ok level 2
                        case cmcReplaceSelect:
                             clipReplace();
                             break;

			// ^Kn Without Undo
			case cmcPutMark0:
			case cmcPutMark1:
			case cmcPutMark2:
			case cmcPutMark3:
			case cmcPutMark4:
			case cmcPutMark5:
			case cmcPutMark6:
			case cmcPutMark7:
			case cmcPutMark8:
			case cmcPutMark9:
			     if (IslineInEdition)
				MarkersInLine[event.message.command-cmcPutMark0]=
				    (int)(inEditPtr-bufEdit);
			     else
				Markers[event.message.command-cmcPutMark0]=
				    (unsigned)(ColToPointer()-buffer);
			     break;

			// ^Qn Without Undo
			case cmcGotoMark0:
			case cmcGotoMark1:
			case cmcGotoMark2:
			case cmcGotoMark3:
			case cmcGotoMark4:
			case cmcGotoMark5:
			case cmcGotoMark6:
			case cmcGotoMark7:
			case cmcGotoMark8:
			case cmcGotoMark9:
                             ClearSelIfNonPers();
                             addToUndo(undoInMov);
			     if (IslineInEdition)
				MakeEfectiveLineInEdition();
			     GotoOffSet(Markers[event.message.command-cmcGotoMark0]);
			     update(ufView);
                             centerCursor=True;
			     break;

			// ^[  Full Ok level 2
			case cmcSearchStart:
                             CheckForShiftSelection();
			     if (IslineInEdition)
				MakeEfectiveLineInEdition();
			     {
			      int Pos;
			      if ((Pos=SearchOpenSymbol('{','}'))!=-1)
				{
                                 addToUndo(undoInMov);
				 GotoOffSet(Pos);
                                 ClearSelIfNonPers();
				 update(ufUpdate);
				}
			     }
			      break;

			// ^]  Full Ok level 2
			case cmcSearchEnd:
                             CheckForShiftSelection();
			     if (IslineInEdition)
				MakeEfectiveLineInEdition();
			     {
			      int Pos;
			      if ((Pos=SearchCloseSymbol('{','}'))!=-1)
				{
                                 addToUndo(undoInMov);
				 GotoOffSet(Pos);
                                 ClearSelIfNonPers();
				 update(ufUpdate);
				}
			     }
			     break;

			// ^(  Full Ok level 2
			case cmcSearchOpPar:
                             CheckForShiftSelection();
			     if (IslineInEdition)
				MakeEfectiveLineInEdition();
			     {
			      int Pos;
			      if ((Pos=SearchOpenSymbol('(',')'))!=-1)
				{
                                 addToUndo(undoInMov);
				 GotoOffSet(Pos);
                                 ClearSelIfNonPers();
				 update(ufUpdate);
				}
			     }
                             break;

			// ^)  Full Ok level 2
			case cmcSearchClPar:
                             CheckForShiftSelection();
			     if (IslineInEdition)
				MakeEfectiveLineInEdition();
			     {
			      int Pos;
			      if ((Pos=SearchCloseSymbol('(',')'))!=-1)
				{
                                 addToUndo(undoInMov);
				 GotoOffSet(Pos);
                                 ClearSelIfNonPers();
				 update(ufUpdate);
				}
			     }
                             break;

			// ^{ is for [  Full Ok level 2
			case cmcSearchOpCor:
                             CheckForShiftSelection();
			     if (IslineInEdition)
				MakeEfectiveLineInEdition();
			     {
			      int Pos;
			      if ((Pos=SearchOpenSymbol('[',']'))!=-1)
				{
                                 addToUndo(undoInMov);
				 GotoOffSet(Pos);
                                 ClearSelIfNonPers();
				 update(ufUpdate);
				}
			     }
                             break;

			// ^} is for ]  Full Ok level 2
			case cmcSearchClCor:
                             CheckForShiftSelection();
			     if (IslineInEdition)
				MakeEfectiveLineInEdition();
			     {
			      int Pos;
			      if ((Pos=SearchCloseSymbol('[',']'))!=-1)
				{
                                 addToUndo(undoInMov);
				 GotoOffSet(Pos);
                                 ClearSelIfNonPers();
				 update(ufUpdate);
				}
			     }
                             break;


			// Shift+Space Full Ok level 2
			case cmcExpandCode:
                             ClearSelIfNonPers();
			     ExpandMacro();
			     break;

			// ^KM Full Ok level 2
			case cmcToUpper:
                             BlockToUpper(True);
			     break;

			// ^KO Full Ok level 2
			case cmcToLower:
                             BlockToLower(True);
			     break;

			// ^Tab Ok level 2
			case cmcSmartIndent:
			     {
			      if (IslineInEdition)
				 MakeEfectiveLineInEdition();

			      int Pos;
			      if ((Pos=SearchOpenSymbol('{','}'))!=-1)
				{
                                 ClearSelIfNonPers();
				 char *s=Pos+buffer;
				 // Back to the start
				 for (;*s!='\n' && s!=buffer; --s);
				 if (*s=='\n') s++;

				 char *s1=Pos+buffer;
				 uint32 x;
				 // Forward to the pos
				 for (x=0; s!=s1; ++s)
				    { AdvanceWithTab(*s,x); }
				 ++x;

				 if (x>(uint32)curPos.x)
				   {
				    EditLine();
                                    if (!IslineInEdition)
                                       break;
                                    Boolean oldOverW=overwrite;
                                    overwrite=False;
				    for (x-=curPos.x;x;--x) InsertCharInLine(32);
                                    overwrite=oldOverW;
				   }
				 update(ufLine);
				}
			     }
			     break;

			// ^ShiftTab Ok level 2
			case cmcSmartUnIndent:
			     {
                              /*if (!IsFirstCharInLine())
                                 break;*/
                              if (!GoFirstCharInLine())
                                 break;
			      if (IslineInEdition)
				 MakeEfectiveLineInEdition();

			      int Pos;
			      if ((Pos=SearchOpenSymbol('{','}'))!=-1)
				{
                                 ClearSelIfNonPers();
				 char *s=Pos+buffer;
				 // Back to the start
				 for (;*s!='\n' && s!=buffer; --s);
				 if (*s=='\n') s++;

				 char *s1=Pos+buffer;
				 uint32 x;
				 // Forward to the pos
				 for (x=0; s!=s1; ++s)
				    { AdvanceWithTab(*s,x); }
				 ++x;

				 if ((uint32)curPos.x>x)
				   {
                                    Boolean oldOverW=overwrite;
                                    overwrite=False;
	                            EditLine();
				    while ((uint32)curPos.x>x)
				      BackSpace();
				    while ((uint32)curPos.x<x)
				      InsertCharInLine(' ');
                                    overwrite=oldOverW;
				   }
				 update(ufLine);
				}
			     }
			     break;

			// ^QL Without Undo
			case cmcSelLength:
			     if (hasSelection() && !selHided)
				editorDialog(edLineLenght,selEnd-selStart);
			     break;

                        // ^J Full Ok Level 2
                        case cmcGotoEditorLine:
                             {
                              int line=curPos.y+1;
                              if (editorDialog(edGotoLine,&line))
                                {
                                 addToUndo(undoInMov);
                                 if (line<0)
                                    line=0;
                                 if (line>limit.y)
                                    line=limit.y;
                                 MoveCursorTo(0,--line);
                                 selStart=(uint32)(curLinePtr-buffer);
                                 selEnd=selStart+LenWithoutCRLF(line,curLinePtr);
                                 centerCursor=True;
                                 update(ufUpdate);
                                }
                              break;
                             }

                        //  Full Ok Level 2
                        case cmcJumpToFunction:
                             {
                              int line;
                              if (editorDialog(edJumpToFunction,&line,buffer,bufLen))
                                {
                                 addToUndo(undoInMov);
                                 if (line<0)
                                    line=0;
                                 if (line>limit.y)
                                    line=limit.y;
                                 MoveCursorTo(0,--line);
                                 selStart=(uint32)(curLinePtr-buffer);
                                 selEnd=selStart+LenWithoutCRLF(line,curLinePtr);
                                 centerCursor=True;
                                 update(ufUpdate);
                                }
                              break;
                             }

                        // ^QB Full Ok Level 2
                        case cmcGoBeginBlock:
                             if (hasVisibleSelection())
                               {
                                addToUndo(undoInMov);
                                if (IslineInEdition)
				   MakeEfectiveLineInEdition();
                                GotoOffSet(selStart);
                                update(ufUpdate);
                               }
                             break;

                        // ^QK Full Ok Level 2
                        case cmcGoEndBlock:
                             if (hasVisibleSelection())
                               {
                                addToUndo(undoInMov);
                                if (IslineInEdition)
				   MakeEfectiveLineInEdition();
                                GotoOffSet(selEnd);
                                update(ufUpdate);
                               }
                             break;

                        // ^KL Full Ok Level 2
                        case cmcMarkLine:
                             if (IslineInEdition)
			        MakeEfectiveLineInEdition();
                             addToUndo(undoInMov);
                             selHided=False;
                             selStart=(uint32)(curLinePtr-buffer);
                             selEnd=selStart+lenLines[curPos.y];
                             curPos.x=0;
                             update(ufView);
                             break;

                        // ^KT Full Ok Level 2
                        case cmcMarkWord:
                             if (IslineInEdition)
			        MakeEfectiveLineInEdition();
                             addToUndo(undoCutInMov,NULL);
                             selHided=False;
                             SelWordUnderCursor();
                             update(ufView);
                             addToUndo(undoCutInMov,NULL);
                             break;

                        // ^KV Full OK Level 2
                        case cmcMoveBlock:
                             if (hasVisibleSelection() && PersistentBlocks &&
                                 clipboard!=0 && clipboard!=this)
                               {
			        if (IslineInEdition)
				   MakeEfectiveLineInEdition();
                                uint32 pos=(uint32)(ColToPointer()-buffer);
                                if (pos<selStart)
                                  {
                                   uint32 x,y;
                                   x=curPos.x; y=curPos.y;
                                   clipCut();
                                   MoveCursorTo(x,y);
                                   clipPaste();
                                   update(ufView);
                                  }
                                else
                                  if (pos>=selEnd)
                                    {
                                     uint32 s,e;
                                     clipCopy();
                                     s=selStart; e=selEnd;
                                     clipPaste();
                                     Markers[8]=selStart;
                                     Markers[9]=selEnd;
                                     selStart=s; selEnd=e;
                                     clipCut();
                                     selStart=Markers[8];
                                     selEnd=Markers[9];
                                     GotoOffSet(selEnd);
                                     update(ufView);
                                    }
                               }
                             break;

                        // ^W  Without Undo
                        case cmcScrollDown:
                             if (delta.y>0)
                               {
			        if (IslineInEdition)
			           MakeEfectiveLineInEdition();
                                delta.y--;
                                if (curPos.y>=delta.y+size.y)
                                   MoveLinesUp(1);
                                update(ufView);
                               }
                             break;

                        // ^Z  Without Undo
                        case cmcScrollUp:
                             if ((unsigned)delta.y<totalLines)
                               {
			        if (IslineInEdition)
			           MakeEfectiveLineInEdition();
                                delta.y++;
                                if (curPos.y<delta.y)
                                   MoveLinesDown(1);
                                update(ufView);
                               }
                             break;

                        // From the menu
                        case cmcSetLocalOptions:
                             {
                              struct {
                                      uint16 t1;
                                      uint16 t2;
                                      char tab[3];
                                     } temp = {0,0,{0,0,0}};
                              temp.t1=CompactFlags();
                              temp.t2=SyntaxHL;
                              sprintf(temp.tab,"%2u",tabSize);
                              if (editorDialog(edSetLocalOptions,&temp))
                                {
                                 ExpandFlags(temp.t1);
                                 SetHighlightTo((shlState)temp.t2);
                                 tabSize=max(atoi(temp.tab),1);
                                 update(ufView);
                                }
                             }
                             break;

                        // From the menu
                        case cmcSetGlobalOptions:
                             SetGlobalOptions();
                             break;

                        case cmcExpandAllTabs:
                             ExpandAllTabs();
                             break;

                        case cmcCompactBuffer:
                             CompactBuffer();
                             break;

                        case cmcRecordMacro:
                             Recording=True;
                             MacroCount=0;
                             break;

                        case cmcStopMacro:
                             Recording=False;
                             break;

                        case cmcPlayMacro:
                             Recording=False;
                             unlock(); // Let all the updates to update the syntax hl.
                             for (i=0; i<MacroCount; i++)
                                {
                                 TEvent e;
                                 if (MacroArray[i]>=0xF000)
                                   {
                                    e.what=evKeyDown;
                                    e.keyDown.charScan.charCode=MacroArray[i]-0xF000;
                                    handleEvent(e);
                                   }
                                 else
                                   {
                                    e.what=evCommand;
                                    e.message.command=MacroArray[i] & 0xFFF;
                                    if (MacroArray[i] & 0x1000)
                                      {
                                       if (ForceSelection==0 ||
                                           ForceSelection==smEndSel)
                                          ForceSelection=smStartSel;
                                       else
                                       if (ForceSelection==smStartSel)
                                          ForceSelection=smExtend;
                                      }
                                    else
                                      {
                                       if (ForceSelection==smExtend ||
                                           ForceSelection==smStartSel)
	                                  ForceSelection = smEndSel;
                                       else
                                       if (ForceSelection==smEndSel)
                                          ForceSelection=0;
                                      }
                                    handleEvent(e);
                                   }
                                }
                             selecting=False;
                             ForceSelection=0;
                             //update(ufView);
                             break;

                        case cmcSelRectStart:
                             FillUndoForRectangularStartEnd(undoRectStart);
                             Xr1=curPos.x;
                             Yr1=curPos.y;
                             selRectHided=False;
                             update(ufView);
                             break;

                        case cmcSelRectEnd:
                             FillUndoForRectangularStartEnd(undoRectEnd);
                             Xr2=curPos.x;
                             Yr2=curPos.y;
                             selRectHided=False;
                             update(ufView);
                             break;

                        case cmcSelRectCopy:
			     if (IslineInEdition)
			        MakeEfectiveLineInEdition();
                             selRectCopy();
                             update(ufUpdate);
                             break;

                        case cmcSelRectPaste:
                             if (selRectClip!=NULL)
                               {
                                if (IslineInEdition)
                                   MakeEfectiveLineInEdition();
                                selRectPaste(selRectClip,curPos.x,curPos.y);
                               }
                             break;

                        case cmcSelRectDel:
			     if (IslineInEdition)
			        MakeEfectiveLineInEdition();
                             selRectDelete(Xr1,Yr1,Xr2,Yr2);
                             break;

                        case cmcSelRectCut:
			     if (IslineInEdition)
			        MakeEfectiveLineInEdition();
                             selRectCopy();
                             selRectDelete(Xr1,Yr1,Xr2,Yr2);
                             break;

                        case cmcSelRectMove:
                             if (IslineInEdition)
                                MakeEfectiveLineInEdition();
                             {
                              int X=curPos.x,Y=curPos.y;
                              
                              selRectCopy();
                              selRectDelete(Xr1,Yr1,Xr2,Yr2);
                              selRectPaste(selRectClip,X,Y);
                             }
                             break;

                        case cmcSelRectHide:
                             addToUndo(undoRectHide,(void *)&selRectHided);
                             selRectHided=Boolean(!selRectHided);
                             update(ufView);
                             break;

                        case cmcLastPosCur:
                             if (UndoSt==undoInMov)
                               {
                                MoveCursorTo(UndoArray[UndoActual].X,UndoArray[UndoActual].Y);
                               }
                             break;

                        case cmcToggleMoveOnPaste:
                             staticNoMoveToEndPaste = staticNoMoveToEndPaste ? False : True;
                             break;

                        case cmcProfileEditor:
                             ProfileEditor();
                             break;

                        case cmcLoadFileUnderCur:
                             if (IslineInEdition)
                                MakeEfectiveLineInEdition();
                             LoadFileUnderCursor(curLinePtr,ColToPointer(),LenWithoutCRLF(curPos.y,curLinePtr));
                             break;

			default:
			    unlock();
                            unlockUndo();
			    return;
			}
                    if (Recording && event.message.command!=cmcRecordMacro)
                      {
                       if (MacroCount<32)
                         {
                          MacroArray[MacroCount++]=event.message.command |
                                                  (selecting ? 0x1000 : 0);
                         }
                      }
		    trackCursor(centerCursor);
		    unlock();
                    unlockUndo();
		    break;
		}
             break;

	case evBroadcast:
	    switch( event.message.command )
		{
		case cmScrollBarChanged:
		     checkScrollBar( event, hScrollBar, delta.x );
		     checkScrollBar( event, vScrollBar, delta.y );
		     break;

                case cmcSetGlobalOptions:
                     ExpandGlobalOptionsLocally((GlobalOptionsRect *)event.message.infoPtr);
                     return;

                case cmcColorsChanged:
                     CacheColors();
                     break;

		default:
		    return;
		}
	}
    clearEvent(event);
}


/****************************************************************************

   Function: void ProfileEditor(void)

   Type: TCEditor member.

   Objetive: Compare the speed of different modes.

   by SET.

****************************************************************************/

void TCEditor::ProfileEditor(void)
{
 int oldDeltaY=delta.y;
 int y=0;
 clock_t t1,t2;
 char buf[80];

 t1=clock();
 while (y<limit.y)
   {
    update(ufView);
    delta.y=y;
    doUpdate();
    y++;
   }
 t2=clock();
 sprintf(buf,_("Speed: %f lines/second"),(y/((t2-t1)/(double)CLOCKS_PER_SEC)));
 messageBox(buf,mfOKButton);
 delta.y=oldDeltaY;
 update(ufView);
}

/****************************************************************************

   Function: void SetGlobalOptions(void)

   Type: TCEditor member.

   Objetive: Sets the statics members calling to the dialog box.

   by SET.

****************************************************************************/

void TCEditor::SetGlobalOptions(void)
{
 struct GlobalOptionsRect temp;
  
 CompactGlobalOptions(&temp);

 if (editorDialog(edSetGlobalOptions,&temp))
   {
    ExpandGlobalOptions(&temp);
    //update(ufView);
   }
}


/****************************************************************************

   Function: void ExpandGlobalOptions(GlobalOptionsRect *temp)

   Type: TCEditor member.

   Objetive: Sets the statics members according to the values of the dialog
             box.

   Parameters:
   temp: The structure filled by the dialog box.

   by SET.

****************************************************************************/

void TCEditor::ExpandGlobalOptions(GlobalOptionsRect *temp)
{
 staticAutoIndent      = (temp->t1 & 1) ? True : False;
 staticUseTabs         = (temp->t1 & 2) ? True : False;
 staticPersistentBlocks= (temp->t1 & 4) ? True : False;
 staticIntelIndent     = (temp->t1 & 8) ? True : False;
 staticCrossCursorInCol= (temp->t1 & 16) ? True : False;
 staticCrossCursorInRow= (temp->t1 & 32) ? True : False;
 staticShowMatchPair   = (temp->t1 & 64) ? True : False;
 staticNoMoveToEndPaste= (temp->t1 & 128) ? True : False;
 staticTransparentSel  = (temp->t1 & 256) ? True : False;
 staticOptimalFill     = (temp->t1 & 512) ? True : False;
 staticTabSize=max(atoi(temp->tab),1);
}


/****************************************************************************

   Function: void CompactGlobalOptions(GlobalOptionsRect *temp)

   Type: TCEditor member.

   Objetive: Compact the statics members

   Parameters:
   temp: The structure to be used by the dialog box.

   by Robert.

****************************************************************************/

void TCEditor::CompactGlobalOptions(GlobalOptionsRect *temp)
{
 temp->t1 = 0;
 if (staticAutoIndent)       temp->t1|=1;
 if (staticUseTabs)          temp->t1|=2;
 if (staticPersistentBlocks) temp->t1|=4;
 if (staticIntelIndent)      temp->t1|=8;
 if (staticCrossCursorInCol) temp->t1|=16;
 if (staticCrossCursorInRow) temp->t1|=32;
 if (staticShowMatchPair)    temp->t1|=64;
 if (staticNoMoveToEndPaste) temp->t1|=128;
 if (staticTransparentSel)   temp->t1|=256;
 if (staticOptimalFill)      temp->t1|=512;

 sprintf(temp->tab,"%2u",staticTabSize);
}


/****************************************************************************

   Function: void ExpandGlobalOptionsLocally(GlobalOptionsRect *temp)

   Type: TCEditor member.

   Objetive: Sets the normal members according to the values of the dialog
             box.

   Parameters:
   temp: The structure filled by the dialog box.

   by SET.

****************************************************************************/

void TCEditor::ExpandGlobalOptionsLocally(GlobalOptionsRect *temp)
{
 autoIndent      = (temp->t1 & 1) ? True : False;
 UseTabs         = (temp->t1 & 2) ? True : False;
 PersistentBlocks= (temp->t1 & 4) ? True : False;
 intelIndent     = (temp->t1 & 8) ? True : False;
 CrossCursorInCol= (temp->t1 & 16) ? True : False;
 CrossCursorInRow= (temp->t1 & 32) ? True : False;
 ShowMatchPair   = (temp->t1 & 64) ? True : False;
 staticNoMoveToEndPaste= (temp->t1 & 128) ? True : False;
 Boolean oldTra=TransparentSel;
 TransparentSel  = (temp->t1 & 256) ? True : False;
 tabSize=max(atoi(temp->tab),1);
 if (TransparentSel!=oldTra)
    SetHighlightTo(SyntaxHL);
 update(ufView);
}

/****************************************************************************

   Function: unsigned GetOffSetOffLine(int y)

   Type: TCEditor member.

   Objetive: Calculates the offset of the start of a line in the buffer.

   Parameters:
   y: the line.

   Returns: The offset.

   by SET.

****************************************************************************/

unsigned TCEditor::GetOffSetOffLine(int y)
{
 int deltaCur=y-curPos.y;

 if (deltaCur==0)
    return (unsigned)(curLinePtr-buffer);

 if (abs(deltaCur)>y)
   {
    unsigned o=0;
    int i=0;
    while (y--)
      o+=lenLines[i++];
    return o;
   }
 else
   {
    if (deltaCur<0)
      {
       deltaCur=-deltaCur;
       unsigned o=(unsigned)(curLinePtr-buffer);
       int i=curPos.y;
       while (deltaCur--)
          o-=lenLines[--i];
       return o;
      }
    else
      {
       unsigned o=(unsigned)(curLinePtr-buffer);
       int i=curPos.y;
       while (deltaCur--)
          o+=lenLines[i++];
       return o;
      }
   }
}


/****************************************************************************

   Function: Boolean selRectCopy()

   Type: TCEditor member.

   Objetive: Copy the selected rectangle into a buffer.

   Returns: False on error.

   by SET.

****************************************************************************/

Boolean TCEditor::selRectCopy(Boolean allowUndo)
{
 // Avoid to be out of buffer
 if ((unsigned)Yr2>totalLines)
    Yr2=totalLines;

 if (!hasRectSel())
    return True;

 int Width=Xr2-Xr1;
 int Height=Yr2-Yr1+1;
 unsigned size=(unsigned)Width*(unsigned)Height+sizeof(struct selRecSt);
 struct selRecSt *auxR;

 // Try to get the memory
 if ((auxR=(struct selRecSt *)malloc(size))==NULL)
    return False;

 if (allowUndo)
    addToUndo(undoRectCopy,auxR);

 // A pointer to the buffer area
 char *b=(char *)(auxR)+sizeof(struct selRecSt);

 // If there is something in the structure kill it.
 //if (selRectClip!=NULL)
 //   delete selRectClip; BUT not here, the UNDO kills that

 selRectClip=auxR;
 auxR->Xr1=Xr1;
 auxR->Xr2=Xr2;
 auxR->Yr1=Yr1;
 auxR->Yr2=Yr2;

 int y,x;
 char *s=buffer+GetOffSetOffLine(Yr1);
 char *sy=s;
 int w;
 char c=' ';
 // Scan the lines inside the rectangle
 for (y=Yr1; y<=Yr2; y++)
    {
     // Initialize vars
     w=0; x=0;
     s=sy;
     // fill untill you reach the right side of the rect
     while (x<Xr2)
       {
        // w is the width of the actual char
        if (!w)
          {
           c=*s;
           s++;
           if (c=='\t')
             { // the tabs don't have 1 char of width
              w=tabSize-(x%tabSize);
              c=' ';
             }
           else
             if (c=='\r' || c==0 || c=='\n')
               { // the end of line is like infinit blanks
                w=MaxLineLen+1;
                c=' ';
               }
             else
               w=1; // The normal case
          }
        if (x>=Xr1)
          { // If is inside the rect copy it
           *b=c;
           b++;
          }
        x++;
        w--;
       }
     // Point to the next line.
     sy+=lenLines[y];
    }

 return True;
}

/****************************************************************************

   Function: void EnsureXDontTab(char *s,int x,int w,char **stop)

   Type: TCEditor member.

   Objetive: Ensure that the zone x to x+w is free of tabs, if a tab is
   found convert it to spaces.
     This routine is very delicated and was made in an easy, but no fast,
   way.

   Notes:
   canUndo must be False to avoid multiple undos.
   Can't be called with a line under edition.

   Parameters:
   s: pointer to the start of the line.
   x: x to start checking.
   w: width of the region.
   stop: returns from where the block delete must delete to eat all the extra
         chars, is NULL is there is no need to delete anything.

   Returns:
   0 process OK.
   1 end of line before the end of process.

   by SET.

****************************************************************************/

int TCEditor::EnsureXDontTab(char *s,int x,int w,char **stop)
{
 int X=0;
 int oldX=0;
 char *lastUsed=s;

 while (X<x)
   {
    oldX=X;
    AdvanceWithTab(*s,X);
    if (!isspace(*s))
       lastUsed=s;
    s++;
    if (!*s || *s=='\r' || *s=='\n')
      {
       *stop=NULL;
       return 1;
      }
   }
 *stop=s;
 if (X!=x)
   {
    unsigned o=(unsigned)(s-buffer);
    deleteRange(s-1,s,False);
    insertSpaces(X-oldX,0,False);
    s=buffer+o+x-oldX;
   }
 while (w--)
   {
    if (*s=='\t')
      {
       unsigned o=(unsigned)(s-buffer);
       deleteRange(s,s+1,False);
       insertSpaces(tabSize-(x%tabSize),0,False);
       s=buffer+o;
      }
    if (!*s || *s=='\r' || *s=='\n')
      {
       *stop=lastUsed+1;
       return 1;
      }
    s++;
    x++;
   }
 return 0;
}

/****************************************************************************

   Function: Boolean selRectPaste(struct selRecSt *st, int X, int Y)

   Type: TCEditor member.

   Objetive: Paste the previously copied rectangle.

   Parameters:
   st: The struct that contains the rectangle.
   X,Y: The insertion point.

   Returns: False on error.

   by SET.

****************************************************************************/

Boolean TCEditor::selRectPaste(struct selRecSt *st, int X, int Y, Boolean allowUndo)
{
 // Filled by hand
 struct UndoCell un;

 if (allowUndo)
   {
    addToUndo(undoPreCopyInfo);
    UndoSaveStartState(un);
   }

 if (X!=curPos.x || Y!=curPos.y)
    MoveCursorTo(X,Y);

 int Width=st->Xr2-st->Xr1;
 int Height=st->Yr2-st->Yr1+1;
 int y=Y;
 char *b=st->s;
 char *stop;
 int cant;

 if ((unsigned)(Y+Height)>totalLines)
   {
    messageBox(_("You can't paste a rectangle crossing the end of the file"),mfError | mfOKButton);
    return False;
   }

 if (allowUndo)
    if (!FillUndoForRectangularPasteClear(Height,un,undoRectPaste))
       return False;

 Boolean oldCanUndo=canUndo;
 canUndo=False;
 while (Height--)
   {
    if (EnsureXDontTab(curLinePtr,X,0,&stop))
      { // The insertion is outside of the real line, don't create extra spaces
       char *sb=b,*sc=b;
       int i=Width;
       while (i--)
         {
          if (!isspace(*sb))
             sc=sb+1;
          sb++;
         }
       cant=(int)(sc-b);
      }
    else
       cant=Width;
    curPos.x=X;
    if (cant)
       insertBuffer(b,0,cant,False,False,False);
    b+=Width;
    curLinePtr+=lenLines[y];
    y++;
    curPos.y=y;
    curPos.x=X;
   }
 Xr1=X;
 Xr2=X+Width;
 Yr1=Y;
 Yr2=Y+st->Yr2-st->Yr1;
 selRectHided=False;
 MoveCursorTo(X,Y);
 canUndo=oldCanUndo;
 return True;
}


/****************************************************************************

   Function: void UndoRectangularPasteClear(UndoCell &un)

   Type: TCEditor member.

   Objetive: Undoes the action made by a paste of a rectangle.
   Is in a separated function because that's a relative complex undo (too
   much variables).

   Parameters:
   un: The UndoCell information.

   The information is stored in s with the following structure:
   char [...]  Buffer with the text affected (the length is in un.Length).
   struct selRectSt of the current state

   by SET.

****************************************************************************/

void TCEditor::UndoRectangularPasteClear(UndoCell &un)
{
 char *s=un.s;
 unsigned size=un.Length;
 struct selRecSt *sr=(struct selRecSt *)(s+size);
 int Y1=sr->Yr1;
 int Y2=sr->Yr2;
 unsigned Height=Y2-Y1+1;
 Y1=sr->Ycur; // In the undo for Paste the cursor isn't in the selection

 char *sLine=buffer+GetOffSetOffLine(Y1);
 char *end_line=sLine;

 // to end_line must be saved
 int y=Y1;
 while (Height--)
   end_line+=lenLines[y++];

 // Put away all the zone
 deleteRange(sLine,end_line,False);
 // Put in the original one
 insertBuffer(s,0,size,False,False,False);

 // Recreate the rectangular selection
 Xr1=sr->Xr1;
 Yr1=sr->Yr1;
 Xr2=sr->Xr2;
 Yr2=sr->Yr2;
 selRectHided=sr->selHide;

 MoveCursorTo(un.X,un.Y);
}


/****************************************************************************

   Function: Boolean FillUndoForRectangularPasteClear(int Height,
             struct UndoCell &un,UndoState st)

   Type: TCEditor member.

   Objetive: Fills the undo cell with the information necesary to undo a
   Paste or a Clear of a rectangular area.

   Parameters:
   Height: of the rectangle.
   un: The UndoCell.
   st: to difference the paste from the Del.

   by SET.

****************************************************************************/

Boolean TCEditor::FillUndoForRectangularPasteClear(int Height,struct UndoCell &un,
        UndoState st)
{
 // from curLinePtr
 char *end_line=curLinePtr;
 unsigned h=Height;
 int y=curPos.y;
 char *aux;

 // to end_line must be saved
 while (h--)
   end_line+=lenLines[y++];

 // Allocate memory for that
 unsigned size=(unsigned)(end_line-curLinePtr);
 unsigned sizer=sizeof(struct selRecSt);
 aux=(char *)malloc(size+sizer);
 if (aux==NULL)
    return False;

 // Save the info of the actual rectangle
 struct selRecSt stact;
 stact.Xr1=Xr1;
 stact.Yr1=Yr1;
 stact.Xr2=Xr2;
 stact.Yr2=Yr2;
 stact.Ycur=curPos.y;
 stact.selHide=selRectHided;

 memcpy(aux,curLinePtr,size);
 memcpy(aux+size,&stact,sizer);

 un.s=aux;
 un.Type=st;
 un.Length=size;

 addToUndo(undoPostCopyInfo,&un);
 return True;
}


/****************************************************************************

   Function: Boolean FillUndoForRectangularStartEnd(UndoState st)

   Type: TCEditor member.

   Objetive: Adds to the undo the info for start and end of rectangular
   selection.

   Parameters:
   st: to difference the start from the end.

   by SET.

****************************************************************************/

Boolean TCEditor::FillUndoForRectangularStartEnd(UndoState st)
{
 struct selRecSt *stact=new selRecSt;

 if (stact==NULL)
    return False;

 if (st==undoRectStart)
   {
    stact->Xr1=Xr1;
    stact->Yr1=Yr1;
    stact->Xr2=curPos.x;
    stact->Yr2=curPos.y;
   }
 else
   {
    stact->Xr1=curPos.x;
    stact->Yr1=curPos.y;
    stact->Xr2=Xr2;
    stact->Yr2=Yr2;
   }
 stact->selHide=selRectHided;

 addToUndo(st,stact);
 return True;
}


/****************************************************************************

   Function: Boolean selRectDelete(int X1, int Y1, int X2, int Y2)

   Type: TCEditor member.

   Objetive: Deletes (Clear) the specified rectangle.

   Parameters:
   X1,Y1: Top left.
   X2,Y2: Bottom right.

   Returns: False on error.

   by SET.

****************************************************************************/

Boolean TCEditor::selRectDelete(int X1, int Y1, int X2, int Y2, Boolean allowUndo)
{
 int Width=X2-X1;
 int Height=Y2-Y1+1;

 // Filled by hand
 struct UndoCell un;

 if (allowUndo)
    UndoSaveStartState(un);

 if (X1!=curPos.x || Y1!=curPos.y)
   {
    MoveCursorTo(X1,Y1);
    if (curPos.y<delta.y)
      {
       trackCursor(True);
       AdjustDrawPtr();   // because we will modify the rest of the lines
      }
   }

 if (allowUndo)
    if (!FillUndoForRectangularPasteClear(Height,un,undoRectDel))
       return False;

 char *stop;

 while (Height--)
   {
    if (EnsureXDontTab(curLinePtr,X1,Width,&stop))
      {
       if (stop!=NULL && *stop!='\r' && *stop!='\n') // If stop==NULL nothing to do
         { // Delete from stop to the end of the line
          deleteRange(stop,curLinePtr+LenWithoutCRLF(curPos.y,curLinePtr),False);
         }
      }
    else
      {
       deleteRange(stop,stop+Width,False);
      }
    curLinePtr+=lenLines[curPos.y++];
   }
 MoveCursorTo(X1,Y1);
 selRectHided=True;
 return True;
}



/****************************************************************************

   Function: uint16 CompactFlags(void)

   Type: TCEditor member.

   Objetive: Compact the Boolean flags of the editor into a word.

   Returns: The compacted word.

   by SET.

****************************************************************************/

uint16 TCEditor::CompactFlags(void)
{
 uint16 t=0;
 if (overwrite)              t|=1;
 if (autoIndent)             t|=2;
 if (UseTabs)                t|=4;
 if (PersistentBlocks)       t|=8;
 if (intelIndent)            t|=16;
 if (CrossCursorInCol)       t|=32;
 if (CrossCursorInRow)       t|=64;
 if (ShowMatchPair)          t|=128;
 if (TransparentSel)         t|=256;
 if (OptimalFill)            t|=512;

 return t;
}


/****************************************************************************

   Function: void ExpandFlags(uint16 t)

   Type: TCEditor member.

   Objetive: Expand a word to the Boolean flags.

   Parameters:
   uint16 t: the word to expand.

   by SET.

****************************************************************************/

void TCEditor::ExpandFlags(uint16 t, Boolean allowUndo)
{
 if (allowUndo)
   {
    if ( overwrite!=((t & 1) ? True : False) )
       toggleInsMode(True);
   }
 else
    overwrite=(t & 1) ? True : False;
 autoIndent             = (t & 2) ? True : False;
 UseTabs                = (t & 4) ? True : False;
 PersistentBlocks       = (t & 8) ? True : False;
 intelIndent            = (t & 16) ? True : False;
 CrossCursorInCol       = (t & 32) ? True : False;
 CrossCursorInRow       = (t & 64) ? True : False;
 ShowMatchPair          = (t & 128) ? True : False;
 TransparentSel         = (t & 256) ? True : False;
 OptimalFill            = (t & 512) ? True : False;
}


/****************************************************************************

   Function: void ExpandAllTabs(void)

   Type: TCEditor member.

   Objetive: Convert all the tabs in the file to spaces.
     The function uses a temporal file to expand the buffer, after the
   operation the cursor is positioned at the top of the file, the selection
   is cleaned and the lenLines array is updated.

   by SET.

****************************************************************************/

void TCEditor::ExpandAllTabs(void)
{
 char *s,*end;
 int x,aux;
 long l;
 FILE *f;
 char *n="exptbtem.tmp";

 if (IslineInEdition)
    MakeEfectiveLineInEdition();
 f=fopen(n,"w+b");
 if (f==NULL)
    return;
 end=buffer+bufLen;
 for (s=buffer,x=0; s<end; s++)
    {
     if (*s=='\t')
       {
        aux=tabSize-(x%tabSize);
        x+=aux;
        while (aux--)
          putc(' ',f);
       }
     else
       {
        putc(*s,f);
        if (*s=='\n')
           x=0;
        else
           x++;
       }
    }
 l=ftell(f);
 if (ferror(f))
   {
    fclose(f);
    return;
   }
 if ((uint32)l!=bufLen && setBufSize((uint32)l))
   {
    rewind(f);
    fread(buffer,(size_t)l,1,f);
    if (ferror(f))
      {
       fclose(f);
       return;
      }
    bufLen=(uint32)l;
    buffer[bufLen]=0;
    RecalculateLineAttributes();
    curLinePtr=buffer;
    curPos.x=curPos.y=0;
    drawLine=drawPtr=0;
    selStart=selEnd=0;
    modified=True;
    update(ufView);
   }
 fclose(f);
 remove(n);
}


/****************************************************************************

   Function: void CompactBuffer(void)

   Type: TCEditor member.

   Objetive: Compact the buffer using tabs to get a smaller file.

   Modified to let the comments and strings untouched as NIK pointed.

   by SET.

****************************************************************************/

void TCEditor::CompactBuffer(void)
{
 int y,x,x1,x2;
 char *s,*r,*end;
 int inString=0,inComment=0,inCppComment;
 int /*extString=0,*/extCppComment=0;

 if (IslineInEdition) // I forgot it and I saw it with a report of Leon
    MakeEfectiveLineInEdition();

 end=buffer+bufLen;
 for (y=0, s=r=buffer; y<=(int)totalLines; y++)
    {
     x=0;
     //inString=extString;
     inCppComment=extCppComment;
     //extString=0;
     extCppComment=0;
     while (*s!='\n' && s<end)
       {
        if (*s==' ' && !inString && !inComment && !inCppComment)
          {
           x1=x;
           while (*s==' ')
             {
              x++;
              s++;
             }
           while ((x2=NextTabPos(x1))<=x)
             {
              *r='\t';
              r++;
              x1=x2;
             }
           while (x1<x)
             {
              *r=' ';
              r++;
              x1++;
             }
          }
        else
          {
           while ((*s!=' ' || inComment || inString || inCppComment) && *s!='\n' && s<end)
             {
              switch (*s)
                {
                 case '\"':
                      if (!inComment && !inCppComment)
                         inString=!inString;
                      break;

                 case '/':
                      if (!inComment && !inString && !inCppComment)
                        {
                         *r=*s; x++; s++; r++;
                         if (*s=='*')
                            inComment=1;
                         else
                            if (*s=='/')
                               inCppComment=1;
                        }
                      break;

                 case '*':
                      if (inComment)
                        {
                         if (*(s+1)=='/')
                           {
                            *r=*s; x++; s++; r++;
                            inComment=0;
                           }
                        }
                      break;

                 case '\\':
                      if (inString)
                        { // Just skip one char
                         *r=*s; x++; s++; r++;
                         //if (*s=='\r' || *s=='\n') The strings are extended automatically
                         //   extString=1;
                        }
                      else
                      if (inCppComment)
                        { // Skip & test for extention
                         *r=*s; x++; s++; r++;
                         if (*s=='\r' || *s=='\n')
                            extCppComment=1;
                        }
                      break;
                }
              AdvanceWithTab(*s,x);
              *r=*s;
              s++; r++;
             }
          }
       }
     if (s<end)
       {
        *r=*s;
        s++; r++;
       }
    }
 if ((unsigned)(r-buffer)!=bufLen) // Any modification
   {
    bufLen=(uint32)(r-buffer);
    buffer[bufLen]=0;
    RecalculateLineAttributes();
    curLinePtr=buffer;
    curPos.x=curPos.y=0;
    selStart=selEnd=0;
    drawLine=drawPtr=0;
    modified=True;
    update(ufView);
   }
}


/****************************************************************************

   Function: void InsertCharInLine(char cVal, Boolean allowUndo)

   Type: TCEditor member.

   Objetive: Insert a char in the edited line.
   Keeps track on:
   1) The selected text.
   2) The markers.
   3) The fucking ASCII 9 (Tab).
   4) The real tabs ;).
   5) The overwrite mode.
   6) The undo.

   Parameter:
   cVal: char to insert.

   by SET.

****************************************************************************/

void TCEditor::InsertCharInLine(char cVal, Boolean allowUndo)
{
 if (!IslineInEdition)
    return;
 // Tab in indent mode
 if (cVal==9 && !UseTabs)
   {
    int Xact=curPos.x,X=0;
    if (curPos.y>0)
      { // Search a hole in the last line
       char *s=curLinePtr-lenLines[curPos.y-1];

       do
	{
	 for (;*s!='\r' && *s!='\n' && !isspace(*s); s++) // While letters
	     { AdvanceWithTab(*s,X); }
	 for (;*s!='\r' && *s!='\n' && isspace(*s); s++)  // While spaces
	     { AdvanceWithTab(*s,X); }
	}
       while (*s!='\r' && *s!='\n' && X<=Xact); // to a mayor X or the end of line
       if (X>Xact)
	  X-=Xact;
       else
	  X=NextTabPos(Xact)-Xact;
      }
    else
      X=NextTabPos(Xact)-Xact;
    for (;X;--X) InsertCharInLine(32);
    return;
   }

 if (overwrite)
   {
    if (allowUndo)
      {
       char vals[2];
       vals[0]=cVal;
       vals[1]=*inEditPtr;
       addToUndo(undoOvrPutChar,(void *)&vals[0]);
      }

    if (*inEditPtr)
      {
       if (*inEditPtr==9) // Is over a Tab?
	  curPos.x=LineWidth(bufEdit,inEditPtr);
       *inEditPtr++=cVal;
       restCharsInLine--;
       //return;
      }
    else
      { // At the end of line
       if (AdjustBufEditFor((int)(inEditPtr-bufEdit+1)))
          return;
       *inEditPtr++=cVal;
       *inEditPtr=0;
      }
   }
 else
   {
    unsigned PosOfIns=(unsigned)(inEditPtr-bufEdit);

    if (allowUndo)
       addToUndo(undoPutChar,(void *)&cVal);

    if (AdjustBufEditFor((int)(inEditPtr-bufEdit+restCharsInLine+1)))
       return;
    if (*inEditPtr)
      {
       if (*inEditPtr==9) // Is over a Tab?
	  curPos.x=LineWidth(bufEdit,inEditPtr);
       memmove(inEditPtr+1,inEditPtr,restCharsInLine+1);
       *inEditPtr++=cVal;
      }
    else
      { // At the end of line
       *inEditPtr++=cVal;
       *inEditPtr=0;
      }

    // Update the markers
    for (int i=0; i<10; i++)
       {
	int Pos=MarkersInLine[i];
	if (Pos>=0 && (unsigned)Pos>=PosOfIns)
	   MarkersInLine[i]++;
       }

    AdjustLineSel((uint32)(inEditPtr-bufEdit-1),1);
   }
 AdvanceWithTab(cVal,curPos.x);
 // Move the screen if the position is outside
 if ((delta.x+size.x-1)<curPos.x)
   {
    delta.x=curPos.x-size.x+8;
    update(ufView);
   }
 if (curPos.y>=delta.y+size.y || curPos.y<delta.y)
    trackCursor(True);
 // If the character is outside the limit adjust it
 if (curPos.x>=limit.x)
    limit.x=curPos.x+1;

 if (ShowMatchPair)
   {
    int pos=-2;

    switch (cVal)
      {
       case '}':
            MakeEfectiveLineInEdition();
            pos=SearchOpenSymbolXY('{','}',XHLC,YHLC);
            break;
       case ')':
            MakeEfectiveLineInEdition();
            pos=SearchOpenSymbolXY('(',')',XHLC,YHLC);
            break;
       case ']':
            MakeEfectiveLineInEdition();
            pos=SearchOpenSymbolXY('[',']',XHLC,YHLC);
            break;
       case '{':
            MakeEfectiveLineInEdition();
            pos=SearchCloseSymbolXY('{','}',XHLC,YHLC);
            break;
       case '(':
            MakeEfectiveLineInEdition();
            pos=SearchCloseSymbolXY('(',')',XHLC,YHLC);
            break;
       case '[':
            MakeEfectiveLineInEdition();
            pos=SearchCloseSymbolXY('[',']',XHLC,YHLC);
            break;
      }
    if (pos!=-2)
      {
       if (pos==-1)
          setStatusLine(_("No match found"));
       else
         {
          int y=YHLC-delta.y;
          int x=XHLC-delta.x;
          XHLCo=curPos.x-1;
          YHLCo=curPos.y;
          if (x>=0 && x<size.x && y>=0 && y<size.y)
             update(ufHLChar);
          else
            {
             char bufaux[80];
             sprintf(bufaux,_("Match found at line %d column %d."),YHLC+1,XHLC+1);
             setStatusLine(bufaux);
            }
         }
      }
   }

 modified=True;
}


/****************************************************************************

   Function: void BlockToUpper(Boolean allowUndo)

   Type: TCEditor member.

   Objetive: Converts all the characters of the selected block to uppercase.

   by SET.

****************************************************************************/

void TCEditor::BlockToUpper(Boolean allowUndo)
{
 if (hasSelection() && !selHided)
   {
    char *s=buffer+selStart;
    char *end=buffer+selEnd;

    // Save all the undo info
    UndoCell un;
    if (allowUndo)
      {
       addToUndo(undoPreCopyInfo);
       UndoSaveStartState(un);
       un.Type=undoToUpper;
       un.Length=(int)(end-s);
       un.s=new char[un.Length];
       if (un.s==NULL) return;
       memcpy(un.s,s,un.Length);
      }

    for (; s<end; s++)
	 *s=toupper(*s);
    modified=True;

    // Add the undo info to the array
    if (allowUndo)
      {
       UndoSaveFinalState(un);
       addToUndo(undoPostCopyInfo,&un);
      }

    update(ufView);
   }
}

/****************************************************************************

   Function: void AdjustLineSel(uint32 pos,int dif)

   Type: TCEditor member.

   Objetive: Adjusts the selLineStart, selNewStart, selLineEnd and selNewEnd
   vars when is needed.

   Parameters:
   pos: Position of the modification.
   dif: Difference of length.

   by SET.

****************************************************************************/

void TCEditor::AdjustLineSel(uint32 pos,int dif, Boolean IncludeStart, Boolean toLeft)
{
  if (selNewStart<selNewEnd)
   {
    int CondStart,CondEnd;
    if (IncludeStart)
      {
       CondStart=pos<=selLineStart;
       CondEnd=pos<=selLineEnd;
      }
    else
      {
       CondStart=pos<selLineStart;
       CondEnd=pos<selLineEnd;
      }

    if (CondStart)
      {
       selLineStart+=dif; selNewStart+=dif;
       selLineEnd+=dif;   selNewEnd+=dif;
      }
    else
      if (CondEnd)
        {
	 selLineEnd+=dif;
         selNewEnd+=dif;
         // If we are deleting characters to left we can delete the point that's the
         // start of the selection and that's must be taked in count.
         if (toLeft)
           {
            int difSt=pos-selLineStart+dif;
            if (dif<0 && difSt<0)
              {
               selLineStart+=difSt;
               selNewStart+=difSt;
              }
           }
        }
      else
        {
         // If we are deleting characters to left we can enter inside the selection
         // even when pos isn't inside.
         if (toLeft)
           {
            int difSt=pos-selLineEnd+dif;
            if (dif<0 && difSt<0)
              {
               selLineEnd+=difSt;
               selNewEnd+=difSt;
              }
           }
        }
   }
}

/****************************************************************************

   Function: void BlockToLower(void)

   Type: TCEditor member.

   Objetive: Converts all the characters of the selected block to lowercase.

   by SET.

****************************************************************************/

void TCEditor::BlockToLower(Boolean allowUndo)
{
 if (hasSelection() && !selHided)
   {
    char *s=buffer+selStart;
    char *end=buffer+selEnd;

    // Save all the undo info
    UndoCell un;
    if (allowUndo)
      {
       addToUndo(undoPreCopyInfo);
       UndoSaveStartState(un);
       un.Type=undoToLower;
       un.Length=(int)(end-s);
       un.s=new char[un.Length];
       if (un.s==NULL) return;
       memcpy(un.s,s,un.Length);
      }

    for (; s<end; s++)
	 *s=tolower(*s);
    modified=True;

    // Add the undo info to the array
    if (allowUndo)
      {
       UndoSaveFinalState(un);
       addToUndo(undoPostCopyInfo,&un);
      }

    update(ufView);
   }
}


/****************************************************************************

   Function: int SearchOpenSymbol(char open, char close)

   Type: TCEditor member.

   Objetive: Search the offset of the { where the cursor is.

   Parameters:
   open: ASCII of the open.
   close: ASCII of the close.

   Return: The offset or -1 if the cursor isn't inside a {}.

   by SET.

****************************************************************************/

int TCEditor::SearchOpenSymbol(char open, char close)
{
 unsigned Count=1;
 char *s=ColToPointer();

 while (s!=buffer)
   {
    if (*--s==open)
      {
       if (!--Count)
	  return (int)(s-buffer);
      }
    else if (*s==close)
	    Count++;
   }
 return -1;
}

/****************************************************************************

   Function: int SearchOpenSymbolXY(char open, char close, int &X, int &Y)

   Type: TCEditor member.

   Objetive: Search the offset, X and Y of the match pair for open indicated
   by close.

   Parameters:
   open: ASCII of the open.
   close: ASCII of the close.
   X,Y: Coordinates of the match.

   Return: The offset or -1 if the cursor isn't inside a {}.

   by SET.

****************************************************************************/

int TCEditor::SearchOpenSymbolXY(char open, char close, int &X, int &Y)
{
 unsigned Count=1;
 char *s=ColToPointer(),*start;

 if (s==buffer)
    return -1;
 --s;
 Y=curPos.y;
 X=0;
 while (s!=buffer)
   {
    if (*--s==open)
      {
       if (!--Count)
         {
          if (Y==0)
             start=buffer;
          else
            {
             for (start=s; *start!='\n'; start--);
             start++;
            }
          while (start!=s)
            {
             AdvanceWithTab(*start,X);
             start++;
            }
	  return (int)(s-buffer);
         }
      }
    else
       if (*s==close)
	  Count++;
       else
          if (*s=='\n')
             Y--;
   }
 return -1;
}

/****************************************************************************

   Function: int SearchCloseSymbolXY(char open, char close, int &X, int &Y)

   Type: TCEditor member.

   Objetive: Search the offset of the } where the cursor is.

   Parameters:
   open: ASCII of the open.
   close: ASCII of the close.

   Return: The offset or -1 if the cursor isn't inside a {}.

   by SET.

****************************************************************************/

int TCEditor::SearchCloseSymbolXY(char open, char close, int &X, int &Y)
{
 unsigned Count=1;
 char *s=ColToPointer();
 char *end=buffer+bufLen,*lastl;

 X=0;
 Y=curPos.y;
 lastl=curLinePtr;
 if (s!=end)
   {
    while (s!=end)
      {
       if (*s==close)
	 {
	  if (!--Count)
            {
             while (lastl!=s)
               {
                AdvanceWithTab(*lastl,X);
                lastl++;
               }
	     return (int)(s-buffer);
            }
	 }
       else
          if (*s==open)
	     Count++;
          else
             if (*s=='\n')
               {
                Y++;
                lastl=s+1;
               }
       s++;
      }
   }
 return -1;
}

/****************************************************************************

   Function: int SearchCloseSymbol(char open, char close)

   Type: TCEditor member.

   Objetive: Search the offset of the } where the cursor is.

   Parameters:
   open: ASCII of the open.
   close: ASCII of the close.

   Return: The offset or -1 if the cursor isn't inside a {}.

   by SET.

****************************************************************************/

int TCEditor::SearchCloseSymbol(char open, char close)
{
 unsigned Count=1;
 int dif;
 char *s=ColToPointer(dif);
 char *end=buffer+bufLen;

 if (s!=end)
   {
    // If the cursor is in a Tab check the first char
    if (dif<=0) s++;
    while (s!=end)
      {
       if (*s==close)
	 {
	  if (!--Count)
	     return (int)(s-buffer);
	 }
       else if (*s==open)
	       Count++;
       s++;
      }
   }
 return -1;
}


/****************************************************************************

   Function: void MakeEfectiveLineInEdition(void)

   Type: TCEditor member.

   Objetive: Put the line in edition inside the buffer.

   by SET.

****************************************************************************/

void TCEditor::MakeEfectiveLineInEdition(void)
{
 int actual,lastChar;
 int SpacesEated;
 char *s;
 for (s=bufEdit,actual=lastChar=0; *s; s++)
    {
     lastChar++;
     if (*s!=9 && *s!=' ')
	actual=lastChar;
    }
 SpacesEated=lastChar-actual;
#ifdef __DJGPP__
 bufEdit[actual++]='\r';
#endif
 bufEdit[actual++]='\n';
 bufEdit[actual]=0;
 if (SpacesEated && selLineEnd>0)
    AdjustLineSel(actual-1,-SpacesEated);

 int old=lenLines[lineInEdition];
 int dif=actual-old;

 if (actual>old)
   {
    if (bufSize<bufLen+dif)
       setBufSize(bufLen+dif);
    memmove(curLinePtr+actual,curLinePtr+old,(size_t)(bufLen-(curLinePtr+old-buffer)));
   }
 else
   {
    memcpy(curLinePtr+actual,curLinePtr+old,(size_t)(bufLen-(curLinePtr+old-buffer)));
   }

 unsigned curLineOff=(unsigned)(curLinePtr-buffer);
 if (selNewStart!=selStart || selNewEnd!=selEnd)
   {
    selStart=selNewStart;
    selEnd=selNewEnd;
    updateFlags|=ufView;
   }

 // Translate the markers
 for (int i=0; i<10; i++)
    {
     int Pos=MarkersInLine[i];
     if (Pos>=0) // It's in this line
	Markers[i]=Pos+curLineOff;
     else
       {
	Pos=Markers[i];
	if ((unsigned)Pos>curLineOff) // It's beyond this line
	   Markers[i]+=dif;
       }
    }

 memcpy(curLinePtr,bufEdit,actual);

 IslineInEdition=False;
 lenLines.setAll(lineInEdition,actual,attrInEdit);
 bufLen+=dif;
}

/****************************************************************************

   Function: void ExpandMacro(void)
	     
   Type: TCEditor member.

   Objetive: Expand a pseudo-macro. The routines looks 2 bytes before the
   cursor position.

   by SET.

****************************************************************************/

void TCEditor::ExpandMacro(void)
{
 unsigned AuxMarkers[3];

 if (IslineInEdition)
    MakeEfectiveLineInEdition();
 char *s=ColToPointer();

 if (s-buffer>=2)
   {
    int i;
    s-=2;

    for (i=0; i<CantCodes &&
       (*((short *)&CodesToReplace[i<<1])!=*((short *)s))
       ; i++);

    if (i<CantCodes)
      {
       unsigned PosCur=0,Pos,Val;

       // Change to the correct mode
       uint16 oldFlags=CompactFlags();
       ExpandFlags(ModesOfPM[i]);

       memset(AuxMarkers,0,3*sizeof(unsigned));
       NotExpandingMacro=False;
       BackSpace();
       BackSpace();
       for (s=TextToPut[i]; *s; s++)
	 {
	  switch (*s)
	    {
	     case '\n': newLine();
			break;
	     case '\b': BackSpace();
			break;
 	     case '@':  if (s[1] == '@') // the user want to insert a '@'
                          {
                           if (!IslineInEdition)
                              EditLine();
                           InsertCharInLine(*s++);
                           break;
                          }
                        if (IslineInEdition)
			  {
			   Pos=(unsigned)((curLinePtr-buffer)+(inEditPtr-bufEdit));
			  }
			else
			   Pos=(unsigned)(ColToPointer()-buffer);
			Val=*++s-0x30;
			if (Val)
			   AuxMarkers[Val-1]=Pos;
			else
			   PosCur=Pos;
			break;
	     default:
		     if (!IslineInEdition)
			EditLine();
		     InsertCharInLine(*s);
	    }
	 }
       NotExpandingMacro=True;
       if (IslineInEdition)
	  MakeEfectiveLineInEdition();
       addToUndo(undoInMov);
       GotoOffSet(PosCur);
       for (i=0; i<3; i++)
	   if (AuxMarkers[i])
	      Markers[i+7]=AuxMarkers[i];

       // return to the original mode
       ExpandFlags(oldFlags);

       update(ufView);
      }
   }
}


//#pragma warn -asc

#define Block ((const char *)(block))

/****************************************************************************

   Function: uint32 scan( const void *block, uint32 size, const char *str )
	     
   Type: Normal function.

   Objetive: Search a string inside the buffer. Case sensitive.
   
   Parameters:
   block: The buffer.
   size:  Size of the buffer.
   str:   The string to search.

   C version by Robert Hhne.

****************************************************************************/

static uint32 scan( const void *block, uint32 size, const char *str )
{
 if (!size) return (UINT_MAX);
 uint32 ret=0;
 while (size--)
   {
    if (Block[ret] == str[0])
      {
       uint32 i=0;
       do
	 {
	   i++;
	   if (!str[i]) return (ret);
	   if (size<i) return (UINT_MAX);
	 }
       while (Block[ret+i] == str[i]);
      }
    ret++;
   }
 return (UINT_MAX);
}
/*
{
    unsigned len = strlen( str );
asm {
    PUSH DS
    LES DI,block
    LDS SI,str
    MOV CX,size
    JCXZ __3
    CLD
    MOV AX,len
    CMP AX,1
    JB __5
    JA __1
    LODSB           // searching for a single character
    REPNE SCASB
    JNE __3
    JMP __5
    }
__1:
asm {
    MOV BX,AX
    DEC BX
    MOV DX,CX
    SUB DX,AX
    JB  __3
    LODSB
    INC DX
    INC DX
    }
__2:
asm {
    DEC DX
    MOV CX,DX
    REPNE SCASB
    JNE __3
    MOV DX,CX
    MOV CX,BX
    REP CMPSB
    JE  __4
    SUB CX,BX
    ADD SI,CX
    ADD DI,CX
    INC DI
    OR  DX,DX
    JNE __2
    }
__3:
asm {
    XOR AX,AX
    JMP __6
    }
__4:
asm SUB DI,BX
__5:
asm {
    MOV AX,DI
    SUB AX,WORD PTR block
    }
__6:
asm {
    DEC AX
    POP DS
    }
    return _AX;
}*/

/****************************************************************************

   Function: uint32 scan( const void *block, uint32 size, const char *str )
	     
   Type: Normal function.

   Objetive: Search a string inside the buffer. No case sensitive.
   
   Parameters:
   block: The buffer.
   size:  Size of the buffer.
   str:   The string to search.

   C version by Robert Hhne.

   ToDo: Put only one strupr for the str.

****************************************************************************/

static uint32 iScan( const void *block, uint32 size, const char *str )
{
 if (!size) return (UINT_MAX);
 uint32 ret=0;
 while (size--)
  {
   if (toupper(Block[ret]) == toupper(str[0]))
     {
      uint32 i=0;
      do
	{
	  i++;
	  if (!str[i]) return (ret);
	  if (size<i) return (UINT_MAX);
	}
      while (toupper(Block[ret+i]) == toupper(str[i]));
     }
   ret++;
  }
 return (UINT_MAX);
}
/*
{
    char s[256];
    unsigned len = strlen( str );
asm {
    PUSH DS
    MOV AX,SS
    MOV ES,AX
    LEA DI,s
    LDS SI,str
    MOV AX,len;
    MOV CX,AX
    MOV BX,AX
    JCXZ __9
    }
__1:
asm {
    LODSB
    CMP AL,'a'
    JB  __2
    CMP AL,'z'
    JA  __2
    SUB AL,20h
    }
__2:
asm {
    STOSB
    LOOP __1
    SUB DI,BX
    LDS SI,block
    MOV CX,size
    JCXZ __8
    CLD
    SUB CX,BX
    JB  __8
    INC CX
    }
__4:
asm {
    MOV AH,ES:[DI]
    AND AH,0xDF
    }
__5:
asm {
    LODSB
    AND AL,0xDF
    CMP AL,AH
    LOOPNE  __5
    JNE __8
    DEC SI
    MOV DX,CX
    MOV CX,BX
    }
__6:
asm {
    REPE CMPSB
    JE  __10
    MOV AL,DS:[SI-1]
    CMP AL,'a'
    JB  __7
    CMP AL,'z'
    JA  __7
    SUB AL,20h
    }
__7:
asm {
    CMP AL,ES:[DI-1]
    JE  __6
    SUB CX,BX
    ADD SI,CX
    ADD DI,CX
    INC SI
    MOV CX,DX
    JNE __4
    }
__8:
asm {
    XOR AX,AX
    JMP __11
    }
__9:
asm {
    MOV AX, 1
    JMP __11
    }
__10:
asm {
    SUB SI,BX
    MOV AX,SI
    SUB AX,wORD PTR block
    INC AX
    }
__11:
asm {
    DEC AX
    POP DS
    }
    return _AX;
}

#pragma warn .asc
*/

/****************************************************************************

   Function: void hideSelect()
	     
   Type: TCEditor member.

   Objetive: Hide the selected area.

   by SET.

****************************************************************************/

void TCEditor::hideSelect()
{
 selecting = False;
 selHided=selHided ? False : True;
 update(ufView);
}


/****************************************************************************

   Function: void MoveLinesUp(int i)
	     
   Type: TCEditor member.

   Objetive: Move the cursor i lines up.

   by SET.

****************************************************************************/

void TCEditor::MoveLinesUp(int i)
{
 if (IslineInEdition)
    MakeEfectiveLineInEdition();
 for (; i && curPos.y; --i)
     curLinePtr-=lenLines[--curPos.y];
 update(ufUpdate);
}

/****************************************************************************

   Function: void MoveLinesDown(int i)
	     
   Type: TCEditor member.

   Objetive: Move the cursor i lines down.

   by SET.

****************************************************************************/

void TCEditor::MoveLinesDown(int i)
{
 if (IslineInEdition)
    MakeEfectiveLineInEdition();
 for (; i && (unsigned)curPos.y<totalLines; --i)
     curLinePtr+=lenLines[curPos.y++];
 update(ufUpdate);
}

/****************************************************************************

   Function: void initBuffer()

   Type: TCEditor member.

   Objetive: Allocate memory for the buffer according to bufSize.

   From Borland's TV 1.03.

****************************************************************************/

void TCEditor::initBuffer()
{
 buffer = new char[bufSize];
}

/****************************************************************************

   Function: BufPlusLen *CreateBufPlusLen(char *s,unsigned l)

   Type: static function

   Objetive: Create a copy of a buffer including the length information
             inside, like a Pascal string.

   Parameters:
   char *s: The buffer.
   unsigned l: The length.

   Return: a BufPlusLen structure pointer to the allocated memory.

   by SET.

****************************************************************************/

static BufPlusLen *CreateBufPlusLen(char *s,unsigned l)
{
 BufPlusLen *p;

 p=(BufPlusLen *)malloc(l+sizeof(BufPlusLen));
 if (p)
   {
    p->len=l;
    memcpy(p->s,s,l);
   }
 return p;
}


static unsigned CalcNeededCharsToFill(int X1, int X2, int tabSize, Boolean OptimalFill)
{
 if (X2<=X1) return 0; // sanity check

 if (OptimalFill)
    return (X2/tabSize-X1/tabSize)+X2%tabSize;
 return X2-X1;
}


static void FillGapInBuffer(int X1, int X2, char *s, int tabSize, Boolean OptimalFill)
{
 if (X2<=X1) return; // sanity check

 if (OptimalFill)
   {
    unsigned i=X2/tabSize-X1/tabSize;
    if (i)
       memset(s,'\t',i);
    s+=i;
    i=X2%tabSize;
    if (i)
       memset(s,' ',i);
   }
 else
    memset(s,' ',X2-X1);
}

/****************************************************************************

   Function: Boolean insertBuffer( char *p, uint32 offset, uint32 length,
				   Boolean allowUndo, Boolean selectText,
                                   Boolean moveToEnd )

   Type: TCEditor member.

   Objetive: Insert a text in the buffer.

   Parameters:
   p: pointer to the source buffer.
   offset: offset in the source buffer.
   length: of the string to insert.
   allowUndo: if True the action is saved in the Undo.
   selecText: True => the insertion becomes selected.
   moveToEnd: If True the cursor is moved to the end of the insertion.

   Return: True if all OK.

   by SET.

****************************************************************************/

Boolean TCEditor::insertBuffer( char *p,
			       uint32 offset,
			       uint32 length,
			       Boolean allowUndo,
			       Boolean selectText,
                               Boolean moveToEnd
			     )
{
 if (!length) return True;

 struct stUndoInsert undoSt;
 undoSt.Eated=0;
 if (allowUndo)  // Just remmember the actual selected area
    addToUndo(undoPreInsert,NULL);

 if (bufLen==0 && bufSize==0)
   { // It's a new buffer?
    bufSize=(unsigned)((length+4096) & 0xFFFFF000L);
    initBuffer();
    setBufLen(0);
   }

 int lar=LenWithoutCRLF(curPos.y,curLinePtr);
 // This information is to complete the one in lar
 int CRLFLenOfTheLine=lenLines[curPos.y]-lar;

 // Calculate the cursor position inside the line
 char *s=curLinePtr;
 int i,x,extraSpaces,pF;
 int TotalToAdd;
 int IncludeFirstLine=1; // The first line is included when SpecialLines is updated
 p+=offset; // That's the real source

 // Walk in the line trying to reach the cursor position to translate that
 // into an offset in the line called pF.
 for (pF=0,x=0; pF<lar && x<curPos.x; s++)
    {
     AdvanceWithTab(*s,x);
     if (IncludeFirstLine && !isspace(*s)) // That's for the SpecialLines
        IncludeFirstLine=0;
     pF++;
    }
 // is outside the real line? AND the inserted text won't destroy the new
 // spaces.
 if (x<curPos.x && IsntEOL(*p))
    extraSpaces=CalcNeededCharsToFill(x,curPos.x,tabSize,OptimalFill);
 else
    extraSpaces=0;
 // s points to the "insertion point"
 s=curLinePtr+pF;
 TotalToAdd=extraSpaces+length;

 // insertion point as offset
 unsigned point=(unsigned)(s-buffer);

 if (IsEOL(*p))
   { // Search for spaces at the end of the new inserted line
    char *s1;
    for (s1=s-1; (*s1==' ' || *s1=='\t') && s1>=curLinePtr; s1--);

    if (s1!=(s-1))
      {
       int dif=(int)(s-s1-1);
       s=s1+1;
       TotalToAdd-=dif;
       pF-=dif;
       lar-=dif;
       undoSt.Eated=CreateBufPlusLen(s,dif);
      }
   }

 undoSt.s=s;

 // Is the buffer enough large?
 {
  uint32 DeltaS=(uint32)(s-buffer); // If we need more space the pointer change
  if (bufSize<bufLen+TotalToAdd+1) // 1 to keep space for a \x0
     if (!setBufSize(bufLen+TotalToAdd+1))
        return False;
  s=buffer+DeltaS;
 }

 lenLines.set(curPos.y,pF);

 // * Insert the buffer
 // first make a hole
 unsigned holeSize=(unsigned)(bufLen-(s-buffer));
 if (holeSize)
   {
    if (TotalToAdd>0)
       memmove(s+TotalToAdd,s,holeSize);
    else
       if (TotalToAdd)
	  memmove(s,s-TotalToAdd,holeSize);
   }

 // Update the selection pointers
 if (selectText)
   {
    selStart=(uint32)(s-buffer);
    selEnd=selStart+TotalToAdd;
    selStart+=extraSpaces;
    selHided=False;
   }
 else
   {
    if (hasSelection())
      {
       if (point<selStart)
	 { // before
	  selStart+=TotalToAdd;
	  selEnd+=TotalToAdd;
	  updateFlags|=ufView;
	 }
       else
	 if (point<selEnd)
	   { // inside
	    selEnd+=TotalToAdd;
	    updateFlags|=ufView;
	   }
	 // else beyond
      }
   }

 // Update markers
 for (i=0; i<10; i++)
    {
     if (Markers[i]>point)
	Markers[i]+=TotalToAdd;
    }

 if (extraSpaces)
   {
    FillGapInBuffer(x,curPos.x,s,tabSize,OptimalFill);
    memcpy(s+extraSpaces,p,length);
    lenLines.set(curPos.y,lenLines[curPos.y]+extraSpaces);
   }
 else
    memcpy(s,p,length);

 if (allowUndo)
   {
    undoSt.l=length;
    addToUndo(undoInsert,(void *)&undoSt);
   }

 bufLen+=TotalToAdd;
 if (!holeSize)
    buffer[bufLen]=0;

 // Walk in the inserted text to see the changes in line lengths
 // Note: x is y.
 int inFirstLine;
 unsigned chars;
 unsigned firstTouchedLine=curPos.y;
 char *firstTouchedP=curLinePtr;

 if (moveToEnd || !staticNoMoveToEndPaste)
   {
    for (s=p,i=0,x=curPos.y,inFirstLine=1,chars=0; (unsigned)i<length; i++,s++,chars++)
       {
        // Is a line feed?
        if (*s=='\n')
          {
           // Is the first line?
           if (inFirstLine)
             {
              // Adjust the len of the first line
              lenLines.set(x,lenLines[x]+chars+1);
              // No more this
              inFirstLine=0;
              // Put the rest of the chars in the following line inserting one
              lenLines.insert(x+1,lar+CRLFLenOfTheLine-pF);
             }
           else
              // Only insert a line
              lenLines.insert(x,chars);
           curLinePtr+=lenLines[x++]; // Move the pointer and the cursor
           curPos.x=0;
           chars=0;
           totalLines++;
          }
        else
          if (*s=='\t')
             MoveWithTab(curPos.x);
          else
             if (IsntEOL(*s))
                curPos.x++;
       }
    curPos.y=x;
    limit.y=totalLines+1;
   }
 else
   {
    for (s=p,i=0,x=curPos.y,inFirstLine=1,chars=0; (unsigned)i<length; i++,s++,chars++)
       {
        // Is a line feed?
        if (*s=='\n')
          {
           // Is the first line?
           if (inFirstLine)
             {
              // Adjust the len of the first line
              lenLines.set(x,lenLines[x]+chars+1);
              // No more this
              inFirstLine=0;
              // Put the rest of the chars in the following line inserting one
              lenLines.insert(x+1,lar+CRLFLenOfTheLine-pF);
             }
           else
             // Only insert a line
             lenLines.insert(x,chars);
           x++;
           chars=0;
           totalLines++;
          }
       }
    limit.y=totalLines+1;
   }
 // There are characters added to the last line?
 if (chars)
    if (inFirstLine)
      {// Only a little text inside the line
       lenLines.set(x,lar+CRLFLenOfTheLine+extraSpaces+chars);
      }
    else
       lenLines.set(x,lenLines[x]+chars-1);

 // If needed adjust the SpecialLines array
 if (SpecialLines!=NULL)
   {
    int fromLine=(int)firstTouchedLine+1;      // Included
    int toLine=x+1;                     // Not Included
    int dif=toLine-fromLine,i;
    if (IncludeFirstLine)
       fromLine--;
    for (i=0; SpecialLines[i]!=splEndOfList; i++)
       {
        if (SpecialLines[i]>=fromLine)
           SpecialLines[i]+=dif;
       }
   }

 // Update the syntax highlight from firstTouchedLine to x
 {
  uint32 i=firstTouchedLine;
  uint16 attr;
  char *end=buffer+bufLen;
  // Prev. line attr
  if (i)
     attr=lenLines.getAttr(i-1);
  else
     attr=0;
  // Recalculate for the inserted block
  for (;i<=(uint32)x;i++)
     {
      firstTouchedP+=LineMeassure(firstTouchedP,end,attr);
      lenLines.setAttr(i,attr);
     }
  // Test for propagation:
  // There are more lines?
  if ((uint32)i<totalLines)
    {
     // Yes, recalculate the following line
     firstTouchedP+=LineMeassure(firstTouchedP,end,attr);
     // Test if there are a propagation
     TestPropagation(lenLines.getAttr(i),attr,firstTouchedP,i+1);
     // Set the recalculated value
     lenLines.setAttr(i,attr);
    }
 }

 if ( !isClipboard() )
    modified=True;
 update(ufView);

 return True;
}


/****************************************************************************

   Function: void deleteRangeLineInEdition(char *from,char *to,int x);

   Type: TCEditor member.

   Objetive: Delete a piece of the buffer in edition.
   Includes from but not to, deletes to-from chars.

   Parameters:
   from: From where.
   to: To where.
   x: -1 => No change, else the new x position.

   This routine must be finished.

   by SET.

****************************************************************************/

void TCEditor::deleteRangeLineInEdition(char *from,char *to,int x)
{
 addToUndo(undoPreDelete,from);
 if (x>=0)
    curPos.x=x;
 addToUndo(undoDelete,to);
 memcpy(from,to,restCharsInLine+1);

 // Update markers
 int start=(int)(from-bufEdit);
 int end=(int)(to-bufEdit);
 int dif=end-start,i;
 for (i=0; i<10; i++)
    {
     int Pos=MarkersInLine[i];
     if (Pos>=0)
       {
        if (Pos>=start && Pos<end)
           MarkersInLine[i]=start;
        else
          if (Pos>=end)
             MarkersInLine[i]-=dif;
       }
    }
 AdjustLineSel(start,-dif,True,x>=0 ? True : False); // I'm not sure about the True
 // The x>=0 is a little complex, if x<0 (-1) the cursor isn't moved so we are
 // deleting to the right of the line, so the toLeft parameter MUST be False.
 // ^T and ^QY deletes the right part and pass -1, ^QH deletes the left part.
 modified=True;
 update(ufLine);
}

/****************************************************************************

   Function: void deleteRange(char *from,char *to,Boolean allowUndo)

   Type: TCEditor member.

   Objetive: Delete a piece of the buffer.
   Includes from but not to, deletes to-from chars.

   Parameters:
   from: From where.
   to: To where.
   allowUndo: True if the action is recorded in the undo array.

   by SET.

****************************************************************************/

void TCEditor::deleteRange(char *from,char *to, Boolean allowUndo)
{
 if (from>=to) return;

 char *fromOrig=from;
 // If the block will let the end of the current line exposed see if
 // there are spaces at the end and eat it.
 if (*to=='\r' || *to=='\n' || !*to)
   {
    while (from!=buffer)
      {
       --from;
       if (*from!=' ' && *from!='\t')
         {
          from++;
          break;
         }
      }
   }

 if (allowUndo)
    addToUndo(undoPreDelete,from);

 // Put the cursor in "from"
 int y=0,x=0;
 char *pos=buffer;
 while (pos<=from)
    pos+=lenLines[y++];
 curPos.y=y-1;
 curLinePtr=pos-lenLines[curPos.y];
 pos=curLinePtr;
 while (pos!=fromOrig)
   {
    AdvanceWithTab(*pos++,x);
   }
 curPos.x=x;
 int IncludeFirstLine = x==0;

 // If the section invalidates the drawPtr force a full recalculation
 if (drawPtr>=selStart)
    drawLine=drawPtr=0;

 // Correct the line lengths
#if 0
 // Old version
 for (pos=from,y=curPos.y; pos<to; pos++)
    {
     lenLines.elArray[y]--;
     if (*pos==0xA)
       {
	if ((unsigned)y<totalLines)
	  {
	   lenLines.elArray[y]+=lenLines.elArray[y+1];
	   lenLines.del(y+1);
	  }
	else
	  {
           if (curPos.y)
	      curLinePtr-=lenLines[--curPos.y];
 	  }
        if (totalLines)
	   totalLines--;
	limit.y=totalLines+1;
       }
    }
#else
 // New optimized one
 y=curPos.y;
 uint32 lenOfThisLine=lenLines[y];
 uint32 nextLine=y+1;
 for (pos=from; pos<to; pos++)
    {
     lenOfThisLine--;
     if (*pos=='\n')
       {
	if ((unsigned)y<totalLines)
	  {
           lenOfThisLine+=lenLines[nextLine++];
	  }
	else
	  {
           if (curPos.y)
	      curLinePtr-=lenLines[--curPos.y];
 	  }
        if (totalLines)
	   totalLines--;
       }
    }
 lenLines.set(y,lenOfThisLine);
 if ((nextLine-y)>1)
   { // If we need to delete lines
    lenLines.deleteRange(y+1,nextLine-1);
    // If needed adjust the SpecialLines array
    if (SpecialLines!=NULL)
      {
       int fromLine=y+1;      // Included
       int toLine=nextLine;   // Not Included
       int l,dif=toLine-fromLine,i;
       if (IncludeFirstLine)
          fromLine--;
       if (*(pos-1)=='\n')
          toLine--;
       for (i=0; SpecialLines[i]!=splEndOfList; i++)
          {
           l=SpecialLines[i];
           if (l>=toLine)
              SpecialLines[i]-=dif;
           else
              if (l>=fromLine)
                 SpecialLines[i]=-1;
          }
      }
   }
 limit.y=totalLines+1;
#endif

 // Correct the Markers
 {
  int i;
  unsigned ToPoint=(unsigned)(to-buffer);
  unsigned FromPoint=(unsigned)(from-buffer);
  for (i=0; i<10; i++)
     {
      if (Markers[i]>ToPoint)
	 Markers[i]-=ToPoint-FromPoint;
      else
	 if (Markers[i]>FromPoint)
	    Markers[i]=FromPoint;
     }
 }

 if (allowUndo)
    addToUndo(undoDeleteBuf,to);

 // do the work
 memcpy(from,to,(size_t)(bufLen-(to-buffer)));
 bufLen-=(unsigned)(to-from);

 // Correct the syntax of the line and test for propagation
 {
  uint16 attr;
  char *s=curLinePtr;
  uint32 y=curPos.y;

  // get the previous line attr
  if (y)
     attr=lenLines.getAttr(y-1);
  else
     attr=0;
  // recalculate the attr of the actual (modified) line
  s+=LineMeassure(s,s+lenLines[y],attr);
  lenLines.setAttr(y,attr);
  // There are more lines?
  if ((uint32)curPos.y<totalLines)
    {
     // Yes, recalculate the following line
     s+=LineMeassure(s,s+lenLines[++y],attr);
     // Test if there are a propagation
     TestPropagation(lenLines.getAttr(y),attr,s,y+1);
     // Set the recalculated value
     lenLines.setAttr(y,attr);
    }
 }

 if (hasSelection())
   {
    uint32 pos1=(uint32)(from-buffer);
    unsigned pos2=(unsigned)(to-buffer);
    unsigned diff=pos2-pos1;
    if (pos1<selStart)
      {
       if (pos2<=selStart)
	 { // pos1<selStart && pos2<=selEnd
	  selStart-=diff;
	  selEnd-=diff;
	 }
       else
	 {
	  if (pos2>selEnd) // All is inside
	     selEnd=selStart=0;
	  else
	    { // a part
	     selStart=pos1;
	     selEnd-=diff;
	    }
	 }
      }
    else
      { // >= selStart
       if (pos1<selEnd)
	 {
	  if (pos2<=selEnd)
	     selEnd-=diff;
	  else
	     selEnd=pos1;
	 }
      }
   }

 modified=True;
 update(ufView);
}


/****************************************************************************

   Function: int LineWidth()

   Type: TCEditor member.

   Objetive: Compute the length of the current line, taking care about tabs.

   Return: The length.

   by SET.

****************************************************************************/

int TCEditor::LineWidth()
{
 char *s;
 int x,off,lar=LenWithoutCRLF(curPos.y,curLinePtr);

 for (s=curLinePtr,x=off=0; off<lar; off++,s++)
    {
     AdvanceWithTab(*s,x);
    }
 return x;
}

/****************************************************************************

   Function: int LineWidth(char *s, char *d)
   
   Type: TCEditor member.

   Objetive: Compute the length of the current line, taking care about tabs.

   Parameters:
   s: pointer to the start of the line.
   d: pointer to the end of the line.

   Return: The length.

   by SET.

****************************************************************************/

int TCEditor::LineWidth(char *s, char *d)
{
 int lar=(int)(d-s);
 int x,off;

 for (x=off=0; off<lar; off++,s++)
    {
     AdvanceWithTab(*s,x);
    }
 return x;
}


/****************************************************************************

   Function: Boolean insertFrom( TEditor *editor )

   Type: TCEditor member.

   Objetive: Insert the selected text of another editor in this editor.

   Return: True = OK.

   From Borland's TV 1.03.

****************************************************************************/

Boolean TCEditor::insertFrom( TCEditor *editor )
{
 return insertBuffer( editor->buffer,
		      editor->selStart,
		      editor->selEnd - editor->selStart,
		      canUndo,
		      True,
                      False
		    );
}

/****************************************************************************

   Function: Boolean insertText( const void *text, unsigned length,
                                 Boolean selectText )

   Type: TCEditor member.

   Objetive: Insert text from another buffer.

   Parameters:
   text: source buffer.
   length: of the text.
   selectText: if the text will be selected after the operation.

   Return: True = OK.

   From Borland's TV 1.03.

****************************************************************************/

Boolean TCEditor::insertText( const void *text, unsigned length, Boolean selectText )
{
 return insertBuffer( (char *)text, 0, length, canUndo, selectText);
}

/****************************************************************************

   Function: void insertSpaces( unsigned length, Boolean canUseTabs )

   Type: TCEditor member.

   Objetive: Insert some spaces in the text.

   Parameters:
   length: number of spaces to insert.
   canUseTabs: True if tabs can be used.

   Note: Don't call this function when there is a line in edition.

   by SET.

****************************************************************************/

void TCEditor::insertSpaces( unsigned length, int X1, Boolean canUseTabs )
{
 if (OptimalFill && canUseTabs)
   {
    unsigned l=CalcNeededCharsToFill(X1,X1+length,tabSize,OptimalFill);
    if (AdjustBufEditFor(l))
       return;
    FillGapInBuffer(X1,X1+length,bufEdit,tabSize,OptimalFill);
    insertText(bufEdit,l,False);
   }
 else
   {
    if (AdjustBufEditFor(length))
       return;
    memset(bufEdit,' ',length);
    insertText(bufEdit,length,False);
   }
}

/****************************************************************************

   Function: uint32 lineMove( uint32 p, int count )

   Type: TCEditor member.

   Objetive: Move the cursor to a position, based on an offset plus a number
   of lines.

   Parameters:
   p: offset of the origin.
   count: number of lines from this point.

   Return:
   The new offset of the cursor in the buffer.

   by SET.

****************************************************************************/

uint32 TCEditor::lineMove( uint32 p, int count )
{
 GotoOffSet(p);
 MoveCursorTo(curPos.x,curPos.y+count);
 return (uint32)(ColToPointer()-buffer);
}

/*
ushort TEditor::lineMove( ushort p, int count )
{
    ushort i = p;
    p = lineStart(p);
    int pos = charPos(p, i);

    while( count != 0 )
	{
	i = p;
	if( count < 0 )
	    {
	    p = prevLine(p);
	    count++;
	    }
	else
	    {
	    p = nextLine(p);
	    count--;
	    }
	}

    if ( p != i )
       p = charPtr(p, pos);
    return p;
}*/


static int AnalizeLineForIndent(char *s,int x,Boolean &mu,int l, int tabSize,
                                int avail)
{
 int Xlocal=x;
 char *ori=s;

 if (*s=='/')
   {
    l--; s++; Xlocal++;
    // If C++ comment ret x.
    if (!l || *s=='/')
       return x;
    // If C comment eat it
    if (*s=='*')
      {
       l--; s++; Xlocal++;
       while (l)
         {
          if (*s=='*')
            {
             l--; s++; Xlocal++;
             if (*s=='/')
                break;
            }
          if (l)
            {
             AdvanceWithTab(*s,Xlocal);
             l--; s++;
            }
         }
       // If the comment continues in the next line ret x.
       if (!l)
          return x;
       // eat all the spaces
       do
        {
         AdvanceWithTab(*s,Xlocal);
         l--; s++;
        }
       while (l && isspace(*s));
       if (!l)
          return x;
      }
    else
      return x; // If is only / ret x.
   }

 char *startWord=s;
 int lenWord=0;
 int xStartWord=Xlocal;

 // Get the first word in the line
 while (l && isWordChar(*s))
   {
    lenWord++;
    l--; s++; Xlocal++;
   }

 // Special cases
 if (!lenWord)
   {
    if (*s=='{')
       return Xlocal+1;
    if (*s=='}' && Xlocal)
      {
       mu=True;
       return x;
      }
   }

 // eat spaces
 while (l && isspace(*s))
   {
    AdvanceWithTab(*s,Xlocal);
    l--; s++;
   }

 // Analize: 1) The balance of (
 //          2) The last usefull char
 //          3) The column of the first ( , in fact the first non-blank after
 int numPar=0;
 char lastUseful=0;
 int xFirstPar=-1;
 while (l)
   {
    switch (*s)
      {
       case '(':
            numPar++;
            lastUseful=*s;
            if (xFirstPar<0)
              {
               while (l>1 && isspace(*(s+1)))
                 {
                  AdvanceWithTab(*s,Xlocal);
                  l--; s++;
                 }
               xFirstPar=Xlocal+1;
              }
            break;

       case ')':
            numPar--;
            lastUseful=*s;
            break;

       case '\"':
            do
             {
              AdvanceWithTab(*s,Xlocal);
              l--; s++;
              if (*s=='\\')
                {
                 l--; s++; Xlocal++;
                }
              else
                if (*s=='\"')
                  {
                   lastUseful=*s;
                   break;
                  }
             }
            while (l);
            break;

       case '\'':
            do
             {
              AdvanceWithTab(*s,Xlocal);
              l--; s++;
              if (*s=='\\')
                {
                 l--; s++; Xlocal++;
                }
              else
                if (*s=='\'')
                  {
                   lastUseful=*s;
                   break;
                  }
             }
            while (l);
            break;

       case '/':
            l--; s++; Xlocal++;
            if (*s=='/')
              {
               l=0;
               break;
              }
            if (*s=='*')
              {
               l--; s++; Xlocal++;
               while (l)
                 {
                  if (*s=='*')
                    {
                     l--; s++; Xlocal++;
                     if (*s=='/')
                        break;
                    }
                  AdvanceWithTab(*s,Xlocal);
                  l--; s++;
                }
              }
            break;

       default:
            if (!isspace(*s))
               lastUseful=*s;
      }
    if (l)
      {
       AdvanceWithTab(*s,Xlocal);
       l--; s++;
      }
   }

 // Here we have a lot of information about the line

 // More ( than ), then goto this col
 if (numPar>0)
    return xFirstPar;

 //   More ) than (, then try to find the command that started all, is
 // heuristic there is no way to make that perfect.
 if (numPar<0)
   {
    // Search the ( than balance the line
    --ori;
    while (avail)
      {
       if (*ori=='(')
         {
          numPar++;
          if (!numPar)
             break;
         }
       else
         if (*ori==')')
            numPar--;
       avail--;
       ori--;
      }
    if (numPar) // unbalanced
      {
       mu=True;
       return x;
      }

    // Now continue until we reach the start of the line
    char *LastUsed=ori;
    --ori;
    --avail;
    while (avail)
      {
       if (*ori=='\n')
          break;
       if (isWordChar(*ori))
          LastUsed=ori;
       if (*ori=='(')
          numPar++;
       else
         if (*ori==')')
            numPar--;
       ori--;
       avail--;
      }

    // The whole line balances it?
    if (numPar)
      { // Nope
       return x;
      }

    // Now try to find the first word
    startWord=LastUsed;
    s=LastUsed;
    lenWord=0;
    xStartWord=0;

    while (isWordChar(*s))
      {
       lenWord++;
       s++;
      }

    // Is a word?
    if (!lenWord)
      { // Nope
       return x;
      }

    // Now we have the word so what's the X position?
    ori++;
    while (ori<LastUsed)
      {
       AdvanceWithTab(*ori,xStartWord);
       ori++;
      }
    x=xStartWord;
   }

 // To help in the next
 int notHaveColon = (lastUseful!=';');

 // Now about the first word
 // A pseudo hand-made hash
 switch (lenWord)
   {
    case 2: if (notHaveColon && ((*startWord=='d' && startWord[1]=='o') ||
                (*startWord=='i' && startWord[1]=='f')))
               return xStartWord+2;
            break;

    case 3: if (notHaveColon && *startWord=='f' && startWord[1]=='o' &&
                startWord[2]=='r')
               return xStartWord+3;
            break;

    case 4: if (*startWord=='e')
              {
               if (strncmp(startWord+1,"lse",3)==0)
                  return xStartWord+2;
               break;
              }
            if (*startWord=='c')
              {
               if (strncmp(startWord+1,"ase",3)==0)
                  return xStartWord+5;
               break;
              }
            break;

    case 5: if (notHaveColon && *startWord=='w')
              {
               if (strncmp(startWord+1,"hile",4)==0)
                  return xStartWord+2;
               break;
              }
            if (*startWord=='b')
              {
               if (strncmp(startWord+1,"reak",4)==0)
                 {
                  mu=True;
                  return x;
                 }
               break;
              }
            break;

    case 6: if (*startWord=='r')
              {
               if (strncmp(startWord+1,"eturn",5)==0)
                 {
                  mu=True;
                  return x;
                 }
               break;
              }
            if (*startWord=='s')
              {
               if (strncmp(startWord+1,"witch",5)==0)
                  return xStartWord+2;
               break;
              }
            break;

    case 7: if (*startWord=='d')
              {
               if (strncmp(startWord+1,"efault",6)==0)
                  return xStartWord+5;
               break;
              }
            break;
   }

 return x;
}


/****************************************************************************

   Function: void newLine()

   Type: TCEditor member.

   Objetive: Put a 13+10 in the buffer.
             Autoindenta.

   by SET.

****************************************************************************/

void TCEditor::newLine()
{
 if (IslineInEdition) // This can be optimized
    MakeEfectiveLineInEdition();
 ClearSelIfNonPers();
#ifdef __DJGPP__
 const char crlf[] = "\r\n";
 insertText(crlf, 2, False);
#else
 const char crlf[] = "\n";
 insertText(crlf, 1, False);
#endif

 if (intelIndent && curPos.y>0)
   {
    // analize the last line
    unsigned larThis,larAnt;
    char *prevLine;
    unsigned firstUsedCol=0,firstColHere;
    int i;
    char *firstUsedPos,*firstUsedHere;

    larThis=lenLines[curPos.y];
    //   The following code searchs the first line located before than the
    // actual line that contains at least 1 character
    prevLine=curLinePtr;
    i=1;
    do
     {
      larAnt=lenLines[curPos.y-i];
      prevLine-=larAnt;
      i++;
     }
#ifdef __DJGPP__
// larAnt <= 2 is an assumtion of CR/LF
// I think, this have to be done in an other way
    while (i<=curPos.y && larAnt<=2);
#else
    while (i<=curPos.y && larAnt<=1);
#endif
    firstUsedPos=prevLine;

    //   This code search the position of the first used char and your
    // Column.
    while (*firstUsedPos==' ' || *firstUsedPos==9)
      {
       AdvanceWithTab(*firstUsedPos,firstUsedCol);
       firstUsedPos++;
       larAnt--;
      }

    // Move the cursor to the first char
    firstColHere=0;
    firstUsedHere=curLinePtr;

    // (The same but in the current line)
    while (*firstUsedHere==' ' || *firstUsedHere==9)
      {
       AdvanceWithTab(*firstUsedHere,firstColHere);
       firstUsedHere++;
      }
    //addToUndo(undoInMov);
    curPos.x=firstColHere;

    unsigned TargetCol=firstUsedCol;
    Boolean makeUnIndent=False;

    TargetCol=AnalizeLineForIndent(firstUsedPos,firstUsedCol,makeUnIndent,
#ifdef __DJGPP__
// Again an assumtion of CR/LF
                                   larAnt-2,tabSize,(int)(firstUsedPos-buffer));
#else
                                   larAnt-1,tabSize,(int)(firstUsedPos-buffer));
#endif

    // Avoid a backspace at the start of the line
    if (!TargetCol && makeUnIndent)
       makeUnIndent=False;

#if 0
    int haveColon=*(curLinePtr-3)==';';

    if (*firstUsedPos=='{')
       TargetCol++;
    else
       if (((strncmp(firstUsedPos,"do",2)==0 || strncmp(firstUsedPos,"while",4)==0 ||
            strncmp(firstUsedPos,"if",2)==0) && !haveColon) ||
            strncmp(firstUsedPos,"else",4)==0 || strncmp(firstUsedPos,"switch",5)==0)
         {
          TargetCol+=2;
         }
       else
         if (strncmp(firstUsedPos,"case",4)==0 || strncmp(firstUsedPos,"default",7)==0)
           {
            /* Old: Is inpractic for switchs with labels
            while (*firstUsedPos!=':' && *firstUsedPos!=0xA)
              {
               TargetCol++;
               firstUsedPos++;
              }
            if (*firstUsedPos==':')
              {
               do
                 {
                  TargetCol++;
                  firstUsedPos++;
                 }
               while (*firstUsedPos==' ' || *firstUsedPos==9);
              }*/
            TargetCol+=5;
           }
         else
           if (strncmp(firstUsedPos,"break",5)==0 || strncmp(firstUsedPos,"return",6)==0)
              makeUnIndent=True;
           else
             if (*firstUsedPos=='}' && TargetCol!=0)
                makeUnIndent=True;
             else
                if (strncmp(firstUsedPos,"for",3)==0 && !haveColon)
                   TargetCol+=3;
#endif

    if ((unsigned)curPos.x<TargetCol)
      {
#ifdef __DJGPP__
// larThis > 2 is an assumtion of CR/LF
// I think, this have to be done in an other way
       if (larThis>2)
#else
       if (larThis>1)
#endif
         { // The line have chars
          insertSpaces(TargetCol-curPos.x,curPos.x);
         }
       else
         {// Is empty, only move the cursor
          curPos.x=TargetCol;
         }
      }
    if (makeUnIndent)
      {
       Boolean oldUseTabs=UseTabs;
       UseTabs=False; // Force the unindent even whe the user isn't in the
                      // rigth mode.
       BackSpace();
       UseTabs=oldUseTabs;
      }
   }
 else
    if (autoIndent && curPos.y>0)
      {
       unsigned larThis,larAnt;
       char *prevLine;
       unsigned firstUsedCol=0,firstColHere;
       int i;
       char *firstUsedPos,*firstUsedHere;

       larThis=lenLines[curPos.y];
       prevLine=curLinePtr;
       i=1;
       do
        {
         larAnt=lenLines[curPos.y-i];
         prevLine-=larAnt;
         i++;
        }
#ifdef __DJGPP__
// larAnt <= 2 is an assumtion of CR/LF
// I think, this have to be done in an other way
       while (i<=curPos.y && larAnt<=2);
#else
       while (i<=curPos.y && larAnt<=1);
#endif
       firstUsedPos=prevLine;
   
       while (*firstUsedPos==' ' || *firstUsedPos==9)
         {
          AdvanceWithTab(*firstUsedPos,firstUsedCol);
          firstUsedPos++;
         }
   
       // Move the cursor to the first char
       firstColHere=0;
       firstUsedHere=curLinePtr;
   
       while (*firstUsedHere==' ' || *firstUsedHere==9)
         {
          AdvanceWithTab(*firstUsedHere,firstColHere);
          firstUsedHere++;
         }
       //addToUndo(undoInMov);
       curPos.x=firstColHere;
   
       if ((unsigned)curPos.x<firstUsedCol)
         {
#ifdef __DJGPP__
// larThis > 2 is an assumtion of CR/LF
// I think, this have to be done in an other way
          if (larThis>2)
#else
          if (larThis>1)
#endif
            { // The line have chars
             if (curPos.x==0)
                insertText(prevLine, (unsigned)(firstUsedPos-prevLine), False);
             else
                insertSpaces(firstUsedCol-curPos.x,curPos.x);
            }
          else
            {// Is empty, only move the cursor
             curPos.x=firstUsedCol;
            }
         }
      }
}

/****************************************************************************

   Function: char *ColToPointer()

   Type: TCEditor member.

   Objetive: Returns a pointer to the "closest" position to curPos.x in the
   buffer.
   Note: more than one col reports the same pointer if the X pos is in a tab.
   Note: if the cursor is outside the buffer the pointer is to the \n.

   Return:
   A char pointer to the cursor position in the buffer.

   by SET.

****************************************************************************/

char *TCEditor::ColToPointer()
{
 char *s=curLinePtr,*end=buffer+bufLen;
 int x,xDest=curPos.x;

 for (x=0; *s!='\r' && *s!='\n' && x<xDest && s<end; s++)
    {
     AdvanceWithTab(*s,x);
    }
 return s;
}

/****************************************************************************

   Function: char *ColToPointer(int &Dif)

   Type: TCEditor member.

   Objetive: Is a variant of ColToPointer()
   Dif is the difference between the point gived and the point desired.
   If Dif is negative the cursor was beyond the end of line
   If Dif is positive the cursor was in a tab

   Return:
   A char pointer to the cursor position in the buffer.

   by SET.

****************************************************************************/

char *TCEditor::ColToPointer(int &Dif)
{
 char *s=curLinePtr;
 int x,xDest=curPos.x;

 for (x=0; *s!='\r' && *s!= '\n' && x<xDest; s++)
    {
     AdvanceWithTab(*s,x);
    }
 Dif=x-xDest;
 return s;
}

/****************************************************************************

   Function: char *ColToPointerPost()

   Type: TCEditor member.

   Objetive: Is another variant of ColToPointer().
   The pointer is to the \r or \n if there is no \r

   Return:
   A char pointer to the cursor position in the buffer.

   by SET.

****************************************************************************/

char *TCEditor::ColToPointerPost()
{
 char *s=curLinePtr;
 int x,xDest=curPos.x;

 for (x=0; *s!='\n' && *s!='\r' && x<xDest; s++)
    {
     AdvanceWithTab(*s,x);
    }
 return s;
}

/****************************************************************************

   Function: void SetStartOfSelecting(uint32 startOffSet)

   Type: TCEditor member.

   Objetive: Set the start of the selected area.

   Parameter:
   startOffSet: new start offset.

   by SET.

****************************************************************************/

void TCEditor::SetStartOfSelecting(uint32 startOffSet)
{
 selStartOffSet=startOffSet;
 if (!selHided && hasSelection())
    update(ufView);
 else
    update(ufLine);
 selHided=False;
 selecting=True;
}

/****************************************************************************

   Function: void UpdateSelecting(void)

   Type: TCEditor member.

   Objetive: Update the selected area according to the new position of the
   cursor.

   by SET.

****************************************************************************/

void TCEditor::UpdateSelecting(void)
{
 uint32 actualPos=(uint32)(ColToPointerPost()-buffer);

 if (actualPos>selStartOffSet)
   {
    selStart=selStartOffSet;
    selEnd=actualPos;
   }
 else
   {
    selStart=actualPos;
    selEnd=selStartOffSet;
   }
}

/****************************************************************************

   Function: void MoveCursor(char *ori,char *dest)

   Type: TCEditor member.

   Objetive: Moves the cursor from one point of the buffer to other based on
   pointers to this location, ori is the actual position of the cursor.
     The funtion computes the \n and the tabs.

   Parameters:
   ori: Pointer to the cursor position.
   dest: Pointer to the new cursor position.

   by SET.

****************************************************************************/

void TCEditor::MoveCursor(char *ori,char *dest)
{
 if (ori>dest)
   {
    while (dest!=ori)
      {
       if (*ori--=='\n')
	  curLinePtr-=lenLines[--curPos.y];
      }
    char *s=curLinePtr;
    curPos.x=0;
    while (s!=dest)
      {
       AdvanceWithTab(*s++,curPos.x);
      }
   }
 else
    while (dest!=ori)
      {
       switch (*ori++)
	 {
	  case '\n': curLinePtr+=lenLines[curPos.y++];
		     curPos.x=0;
		     break;
	  case '\t': MoveWithTab(curPos.x);
		     break;
	  case '\r': break;
	  default:   curPos.x++;
	 }
      }
}


/****************************************************************************

   Function: int prevWord()

   Type: TCEditor member.

   Objetive: Move the cursor to the previous word in the text.

   Return:
   How many characters was moved the cursor.

   by SET.

****************************************************************************/

int TCEditor::prevWord(Boolean moveCursor)
{
 char *p=ColToPointer();
 if (p==buffer)
    return 0;
 char *ori=p;

 if (isWordChar(*p) && isWordChar(*(p-1)))
   { // If we are inside a word (not at start or outside)
    // Move to the start
    while (p>buffer &&  isWordChar(*p)) p--;
    // Adjust
    if (p<ori) p++;
   }
 else
   {
    // Get out of the start of the word or the EOL or we'll stay here
    if (isWordChar(*p) || IsEOL(*p))
       p--;
    // Skip the spaces but stop in EOLs
    while (p>buffer && !isWordChar(*p) && IsntEOL(*p)) p--;
    if (isWordChar(*p))
      { // We found a word
       // Go to the start
       while (p>buffer &&  isWordChar(*p)) p--;
       // Adjust
      if (!isWordChar(*p)) p++;
      }
    else
       // We found an EOL so if is a DOS file move to the CR or it will bomb
       if (p>buffer && *(p-1)=='\r') p--;
   }
 if (p>ori)
    p=ori;
 else
    if (moveCursor)
       MoveCursor(ori,p);
 return (int)(p-ori);
}
 
/****************************************************************************

   Function: int nextWord()

   Type: TCEditor member.

   Objetive: Move the cursor to the next word in the text.

   Return:
   How many characters was moved the cursor.
   See nextCWord() for comments, it almost the same but uses !isWord...
   instead of isspace.

   by SET.

****************************************************************************/

int TCEditor::nextWord()
{
 int dif;
 char *p=ColToPointer(dif);
 char *ori=p;
 char *end=buffer+bufLen;

 if (p==end)
    return 0;

 if (dif>0)
    p--;

 if (IsEOL(*p))
   {
    p+=LenEOL;
    if (p>=end)
       return 0;
   }
 else
   {
    if (!isWordChar(*p))
       while (p<end && IsntEOL(*p) && !isWordChar(*p)) p++;
    else
       while (p<end && isWordChar(*p)) p++;
   }
 if (IsntEOL(*p))
    while (p<end && !isWordChar(*p) && IsntEOL(*p)) p++;
 if (p==end) p--;
 if (ori>p)
    p=ori;
 else
    MoveCursor(ori,p);
 return (int)(p-ori);
}

/****************************************************************************

   Function: int nextCWord()

   Type: TCEditor member.

   Objetive: Move the cursor to the next word in the text but stoping in
   any symbol.
     Used by DeleteWord
     Here is how it works:
   1 If we are at the end of line skip the EOL and goto 4.
   2 else If we are outside a word skip all the non-word chars (spaces and
     symbols) stopping if we reach the EOL and goto 4.
   3 else skip the word.
   4 If we aren't at the EOL skip all the SPACES but stop if an EOL is reached.

   What's the effect?
   a) If we are at the end of a line the line is concatenated with the next
      line but the spaces are deleted.
   b) Never delete a word+symbols in one pass.
   c) Ever stop at EOLs to avoid deleting various lines.

   That's how BC behaves (or very close to ...) and that's what I spect.

   Return:
   How many characters was moved the cursor.

   by SET.

****************************************************************************/

int TCEditor::nextCWord()
{
 int dif;
 char *p=ColToPointer(dif);
 char *ori=p;
 char *end=buffer+bufLen;

 if (p==end)
    return 0;

 // Count the tab later
 if (dif>0)
    p--;

 if (IsEOL(*p))
   { // If we are at the end of the line delete the EOL
    p+=LenEOL;
    if (p>=end)
       return 0;
   }
 else
   { // If not:
    if (!isWordChar(*p))
       // If we are in a non-word delete the separations but NOT the word
       while (p<end && IsntEOL(*p) && !isWordChar(*p)) p++;
    else
       // If we are in a word delete up-to the end
       while (p<end && isWordChar(*p)) p++;
   }
 // Eat ONLY the remaining spaces
 if (IsntEOL(*p))
    while (p<end && isspace(*p) && IsntEOL(*p)) p++;
 // Here are some safety checks that don't remmember when are needed
 if (p==end) p--;
 if (ori>p)
    p=ori;
 else
    MoveCursor(ori,p);
 return (int)(p-ori);
}

#ifdef __DJGPP__
#include <pc.h>
#include <dos.h>
#endif

void TCEditor::Beep(void)
{
#ifdef __DJGPP__
 sound(1000);
 delay(100);
 nosound();
#endif
}


/****************************************************************************

   Function: void AdjustBufEditFor(int lar)

   Type: TCEditor member.

   Objetive: Adjust the length of the bufEdit buffer to support lar chars.
   limit.x is adjusted too. The function reallocates the buffer for this
   reason inEditPtr is updated.

   Parameters:
   lar: Desired legth.

   Returns:
   0 = OK.
   1 = Impossible.

   by SET.

****************************************************************************/

int TCEditor::AdjustBufEditFor(int lar)
{
 if (lar>bufEditLen)
   {
    char *s=bufEdit;

    if (lar>MaxLineLen)
      {
       Beep();
       return 1;
      }
    if (limit.x<=lar)
       limit.x=lar+1;
    bufEditLen=limit.x+min(DeltaLineLen,MaxLineLen-limit.x);
    if ((s=(char *)realloc(bufEdit,bufEditLen+4))!=NULL)
      {
       inEditPtr=s+(int)(inEditPtr-bufEdit);
       bufEdit=s;
       return 0;
      }
    Beep();
    return 1;
   }
 return 0;
}


/****************************************************************************

   Function: void EditLine()

   Type: TCEditor member.

   Objetive: Start the edition of the line under the cursor.

   by SET.

****************************************************************************/

void TCEditor::EditLine()
{
 int i;

 lineInEdition=curPos.y;

 // Copy the line into the edition buffer
 int lar=LenWithoutCRLF(lineInEdition,curLinePtr);

 unsigned startLine=(unsigned)(curLinePtr-buffer);
 unsigned endLine=startLine+lar;

 // See if we have enough buffer for this line.
 if (AdjustBufEditFor(max(lar,limit.x-1)))
   {
    if (lar==MaxLineLen+1)
       return;
    if (editorDialog( edLineOverflow )==cmYes)
      {
       int X=curPos.x;
       addToUndo(undoInMov);
       Boolean oldAI=autoIndent;
       autoIndent=False;
       curPos.x=MaxLineLen;
       newLine();
       addToUndo(undoInMov);
       MoveCursorTo(X,curPos.y-1);
       autoIndent=oldAI;
       if (AdjustBufEditFor(max(lar,limit.x-1)))
          return;
      }
    else
       return;
   }

 IslineInEdition=True;
 memcpy(bufEdit,curLinePtr,lar);
 bufEdit[lar]=0;
 // Calculate the position inside the buffer
 for (inEditPtr=bufEdit, i=0; i<curPos.x && *inEditPtr;
      inEditPtr++)
    {
     AdvanceWithTab(*inEditPtr,i);
    }
 if (i>curPos.x) // Only when the cursor is over a tab
    inEditPtr--;

 // Is enough large to hold the cursor pos?
 int added=0;
 if (i<curPos.x)
   { // Nop, insert spaces
    added=CalcNeededCharsToFill(i,curPos.x,tabSize,OptimalFill);
    FillGapInBuffer(i,curPos.x,bufEdit+lar,tabSize,OptimalFill);
    inEditPtr=bufEdit+lar+added;
    lar+=added;
    *inEditPtr=0;
   }
 restCharsInLine=lar-(int)(inEditPtr-bufEdit);

 selNewStart=selStart;
 selNewEnd=selEnd;

 if (hasSelection())
   {
    // If we added spaces and the spaces are inside of the seleccion take care about it
    if (added && selEnd>endLine)
      {
       if (selStart>endLine)
         {
          //added++;
          selNewEnd+=added;
          selNewStart+=added;
         }
       else
          selNewEnd+=added;
      }
    if (selStart<=startLine)
      {
       if (selNewEnd>startLine) // No for New
	 {
	  selLineStart=0;
	  selLineEnd=selNewEnd-startLine; // No for New
	 }
       else
	 { selLineStart=selLineEnd=0; }
      }
    else
      {
       if (selNewStart<endLine) // No for New
	 {
	  selLineStart=selNewStart-startLine;  // No for New
	  selLineEnd=selNewEnd-startLine; // No for New
	 }
       else
	 { selLineStart=selLineEnd=lar+1; } // Out off the line
      }
   }
 else
   {
    selLineStart=0;
    selLineEnd=0;
   }

 // Translate the markers
 for (i=0; i<10; i++)
    {
     unsigned Pos=Markers[i];
     if (startLine<=Pos && Pos<endLine)
	MarkersInLine[i]=Pos-startLine;
     else
	MarkersInLine[i]=-1;
    }

 // Copy the original attribute
 attrInEdit=lenLines.getAttr(lineInEdition);
}

/****************************************************************************

   Function: void replace()

   Type: TCEditor member.

   Objetive: Create the dialog for Search & Replace and execute it.

   by SET.

****************************************************************************/

void TCEditor::replace()
{
 char *Word;
 int ret;

 if ((Word=WordUnderCursor(80))!=NULL)
   {
    strcpy(findStr,Word);
    delete Word;
   }

 TReplaceCDialogRec replaceRec( findStr, replaceStr, editorFlags, SearchInSel, FromWhere  );
 if ( (ret=editorDialog( edReplace, &replaceRec )) != cmCancel )
   {
    strcpy( findStr, replaceRec.find );
    strcpy( replaceStr, replaceRec.replace );
    editorFlags = replaceRec.options | efDoReplace;
    if (ret==cmYes)
        editorFlags |= efReplaceAll;
    SearchInSel = replaceRec.in_sel;
    FromWhere = replaceRec.from;
    if (FromWhere)
       StartOfSearch=0; // All
    else
       StartOfSearch=(unsigned)(ColToPointer()-buffer);
    doSearchReplace();
   }
}

/****************************************************************************

   Function: void scrollTo( int x, int y )

   Type: TCEditor member.

   Objetive: Adjust the delta to make the x,y point visible.

   Parameters:
   x,y cursor position.

   From Borland's TV 1.03.

****************************************************************************/

void TCEditor::scrollTo( int x, int y )
{
 x = max(0, min(x, limit.x - size.x));
 y = max(0, min(y, limit.y));  // - size.y cutted
 if ( x != delta.x || y != delta.y )
   {
    delta.x = x;
    delta.y = y;
    update(ufView);
   }
}

/****************************************************************************

   Function: Boolean search( const char *findStr, unsigned opts )

   Type: TCEditor member.

   Objetive: Make a Search with/out Replace calling scan and iScan.

   Parameters:
   findStr: The string to search.
   opts: flags to indicate the action and type of search.

   by SET.

****************************************************************************/

Boolean TCEditor::search( const char *findStr, unsigned opts )
{
 unsigned pos,end_s;
 unsigned i;

 if (SearchInSel)
   {
    pos=max(StartOfSearch,selStart);
    end_s=selEnd;
   }
 else
   {
    pos=StartOfSearch;
    end_s=bufLen;
   }

 do
  {
   if (pos>=end_s)
      i=sfSearchFailed;
   else
     {
      if ( (opts & efCaseSensitive) != 0 )
         i = scan( &buffer[pos], end_s - pos, findStr);
      else
         i = iScan( &buffer[pos], end_s - pos, findStr);
     }

   if ( i != sfSearchFailed )
     {
      i += pos;
      if ( (opts & efWholeWordsOnly) == 0 ||
	  !(
	    ( i != 0 && isWordChar(bufChar(i - 1)) != 0 ) ||
	    ( i + strlen(findStr) != bufLen &&
		  isWordChar(bufChar(i + strlen(findStr)))
	    )
	  ))
	 {
	  lock();
          selStartF = i;
          selEndF   = i + strlen(findStr);
          addToUndo(undoInMov);
          GotoOffSet(i);
          update(ufView | ufFound);
	  //setSelect(i, i + strlen(findStr), False);
	  trackCursor((!cursorVisible()) ? True : False);
	  unlock();
	  return True;
	 }
      else
	  pos = i + 1;
     }
   }
  while( i != sfSearchFailed );
 return False;
}

/****************************************************************************

   Function: uint16 LineMeassureC(char *s, char *end, uint16 &Attr)
             uint16 LineMeassurePascal(char *s, char *end, uint16 &Attr)
             uint16 LineMeassureClipper(char *s, char *end, uint16 &Attr)

   Type: Static function.

   Objetive: Meassure the length of the line and calculate the syntax
   highlight flags.
     There are one for each syntax highlight system.

   Parameters:
   char *s: Pointer to the start of the line.
   char *end: Pointer to the end of the buffer.
   uint16 &Attr: In => Attribute of the previous line.
                 Out => Attribute of this line.

   Returns:
   The length of the line.

   Notes:
   for C:
   Added support for strings that have a \ at the end of a line (by Robert).
   Added support for // \ feature of gcc.

   by SET.

****************************************************************************/


static uint16 LineMeassureC(char *s, char *end, uint16 &Attr)
{
 uint32 l=0;
 char *end2=end-1;
 int in_char=0;
 int in_string=0;
 int in_com=0;
 int in_prepro=0;
 int firstchar=1;
 uint32 attr=Attr;

 if (attr & ExtCom)
   {
    attr|=InsideCom | StartInCom;
    attr&=Not_ExtCom2;
    in_com=1;
   }
 else
   if (attr & ExtCom2)
     {
      attr|=InsideCom | StartInCom;
      attr&=Not_ExtCom2;
      in_com=1;
     }
   else
      attr&=Not_InsideCom & Not_StartInCom;

 if (!(attr & ExtPrepro))
    attr&=Not_Prepro;
 else
    in_prepro=1;

 if (attr & ExtString)
    in_string = 1;

 attr&=FilterHere;

 if (in_string)
    attr|=StartString;

 while (s<end && *s!='\n')
   {
    if (*s=='\'')
      {
       if (!in_prepro && !in_com && !in_string)
         {
	  in_char=!in_char;
          firstchar=0;
         }
      }
    else
      if (*s=='\"')
	{
	 if (!in_prepro && !in_com && !in_char)
           {
	    in_string=!in_string;
            firstchar=0;
           }
	}
      else
        // A line ended with \ is concatenated with the next line
        if (*s=='\\' && (s==end2 || *(s+1) == '\n' || *(s+1)=='\r'))
          {
           if (in_string)
              attr|=ExtString;
           else
             if (in_com) /*(attr & (ComInside | InsideCom | StartInCom))*/
                attr|=ExtCom2;
             else
                if (in_prepro)
		   attr|=ExtPrepro;
          }
        else
           if (*s=='\\' && (in_string || in_char))
             {
              s++;
              l++;
             }
           else
	      if (!in_string && !in_char)
	        {
	         switch (*s)
	           {
	            case '/':
		         if (!in_com && s<end2)
		           {
		            s++;
		            if (*s=='/')
			      {
			       in_com=1;
			       attr|=ComInside;
			       if (firstchar)
			          attr|=InsideCom;
			       l++;
			      }
		            else
			      if (*s=='*')
			        {
			         in_com=1;
			         attr|=StartCom | ExtCom;
			         if (firstchar)
			            attr|=InsideCom;
			         l++;
			        }
			      else
			        --s;
		           }
                         firstchar=0;
		         break;

	            case '*':
		         if (s<end2)
		           {
		            s++;
		            if (*s=='/' && !(attr & ComInside) && (attr & (ExtCom | InsideCom)))
			      {
			       in_com=0;
			       attr|=EndCom;
			       attr&=Not_ExtCom & Not_InsideCom;
			       l++;
			      }
		            else
			      --s;
		           }
                         firstchar=0;
		         break;

	            case '#':
		         if (firstchar)
		           {
		            firstchar=0;
		            in_prepro=1;
		            attr|=Prepro;
		           }
		         break;

	            default:
		         if (firstchar && !isspace(*s))
		            firstchar=0;
	           }
	        }
    ++l;
    ++s;
   }
 // I saw that in a source of John (aka Fighteer), the string is propagated.
 if (in_string)
    attr|=ExtString;
 Attr=attr;
#if 0
 if (l && *s==0xA) l++;
#else
 if (*s == '\n') l++;
#endif
 return l;
}


static uint16 LineMeassurePascal(char *s, char *end, uint16 &Attr)
{
 uint32 l=0;
 char *end2=end-1;
 int in_string=0;
 int in_com1=0;
 int in_com2=0;
 int in_prepro = 0;
 int firstchar=1;
 uint32 attr=Attr;

 if (attr & ExtCom)
   {
    attr|=InsideCom | StartInCom;
    in_com1=1;
   }
 else
 if (attr & ExtCom2)
   {
    attr|=InsideCom2 | StartInCom2;
    in_com2=1;
   }
 else
    attr&=Not_InsideCom & Not_StartInCom & Not_InsideCom2 & Not_StartInCom2;

 if (!(attr & ExtPrepro))
    attr&=Not_Prepro;
 else
    in_prepro=1;

 attr&=FilterHere;

 while (s<end && *s!='\n')
   {
    if (*s=='\'')
      {
       if (!in_prepro && !in_com1 && !in_com2)
         {
	  in_string=!in_string;
          firstchar=0;
         }
      }
    else
      if (*s=='\\' && (s==end2 || *(s+1) == '\n' || *(s+1)=='\r'))
       {
         if (in_prepro)
             attr|=ExtPrepro;
       }
    else
      if (!in_string)
	{
	 switch (*s)
	   {
            case '#':
	         if (firstchar)
	           {
	            firstchar=0;
	            in_prepro=1;
	            attr|=Prepro;
	           }
	         break;

	    case '(':
		 if (!in_com1 && !in_com2 && s<end2)
		   {
		    s++;
		    if (*s=='*')
		      {
		       in_com1=1;
		       attr|=StartCom | ExtCom;
		       if (firstchar)
			  attr|=InsideCom;
		       l++;
		      }
		    else
		      --s;
		   }
                 firstchar=0;
		 break;

	    case '{':
		 if (!in_com1 && !in_com2)
		   {
		    in_com2=1;
		    attr|=StartCom2 | ExtCom2;
		    if (firstchar)
		       attr|=InsideCom2;
		   }
                 firstchar=0;
		 break;

	    case '*':
		 if (s<end2 && !in_com2)
		   {
		    s++;
		    if (*s==')' && !(attr & ComInside) && (attr & (ExtCom | InsideCom)))
		      {
		       in_com1=0;
		       attr|=EndCom;
		       attr&=Not_ExtCom & Not_InsideCom;
		       l++;
		      }
		    else
		      --s;
		   }
                 firstchar=0;
		 break;

	    case '}':
		 if (!in_com1 && !(attr & ComInside) && (attr & (ExtCom2 | InsideCom2)))
		   {
		    in_com2=0;
		    attr|=EndCom2;
		    attr&=Not_ExtCom2 & Not_InsideCom2;
		   }
                 firstchar=0;
		 break;

	    default:
		 if (firstchar && !isspace(*s))
		    firstchar=0;
	   }
	}
    ++l;
    ++s;
   }
 Attr=attr;
#if 0
 if (l && *s==0xA) l++;
#else
 if (*s == '\n') l++;
#endif
 return l;
}



static uint16 LineMeassureClipper(char *s, char *end, uint16 &Attr)
{
 uint32 l=0;
 char *end2=end-1;
 char *end3=end-3;
 int in_char=0;
 int in_string=0;
 int in_com=0;
 int in_prepro=0;
 int firstchar=1;
 uint32 attr=Attr;

 if (attr & ExtCom)
   {
    attr|=InsideCom | StartInCom;
    in_com=1;
   }
 else
    attr&=Not_InsideCom & Not_StartInCom;
 if (!(attr & ExtPrepro))
    attr&=Not_Prepro;
 else
    in_prepro=1;
 attr&=FilterHere;

 while (s<end && *s!='\n')
   {
    if (*s=='\'')
      {
       if (!in_prepro && !in_com && !in_string)
         {
	  in_char=!in_char;
          firstchar=0;
         }
      }
    else
      if (*s=='\"')
	{
	 if (!in_prepro && !in_com && !in_char)
           {
	    in_string=!in_string;
            firstchar=0;
           }
	}
      else
	if (!in_string && !in_char)
	  {
	   switch (*s)
	     {
	      case '/':
		   if (!in_com && s<end2)
		     {
		      s++;
		      if (*s=='/')
			{
			 in_com=1;
			 attr|=ComInside;
			 if (firstchar)
			    attr|=InsideCom;
			 l++;
			}
		      else
			if (*s=='*')
			  {
			   in_com=1;
			   attr|=StartCom | ExtCom;
			   if (firstchar)
			      attr|=InsideCom;
			   l++;
			  }
			else
			  --s;
		     }
                   firstchar=0;
		   break;
		   
	      case '&':
		   if (!in_com && s<end2)
		     {
		      s++;
		      if (*s=='&')
			{
			 in_com=1;
			 attr|=ComInside;
			 if (firstchar)
			    attr|=InsideCom;
			 l++;
			}
		      else
		  	--s;
		     }
                   firstchar=0;
		   break;

	      case '*':
		   if (s<end2)
		     {
		      s++;
		      if (*s=='/' && !(attr & ComInside) && (attr & (ExtCom | InsideCom)))
			{
			 in_com=0;
			 attr|=EndCom;
			 attr&=Not_ExtCom & Not_InsideCom;
			 l++;
			}
		      else
		        if (!(attr & ComInside) && !(attr & InsideCom) &&
		             s<end3 && *s==' ' && *(s+1)=='-')
		          {
			   in_com=1;
			   attr|=ComInside;
			   if (firstchar)
			      attr|=InsideCom;
			   s+=2;
			   l+=3;
		          }
		        else
			  --s;
		     }
                   firstchar=0;
		   break;

	      case ';':
		   if ((s==end2 || *(s+1) == '\n' || *(s+1)=='\r') && in_prepro)
		      attr|=ExtPrepro;
                   firstchar=0;
		   break;

	      case '#':
		   if (firstchar)
		     {
		      firstchar=0;
		      in_prepro=1;
		      attr|=Prepro;
		     }
		   break;

	      default:
		   if (firstchar && !isspace(*s))
		      firstchar=0;
	     }
	  }
    ++l;
    ++s;
   }
 Attr=attr;
#if 0
 if (l && *s==0xA) l++;
#else
 if (*s == '\n') l++;
#endif
 return l;
}



/****************************************************************************

   Function: void setBufLen( uint32 length )

   Type: TCEditor member.

   Objetive: Set the length of the buffer, that's very different to the
   size, the length is the *used* part, the size is the amount of memory
   allocated (>= length).
     That forces an initialization of all the variables.

   Parameters:
   length: length of the buffer.

   by SET.

****************************************************************************/

void TCEditor::setBufLen( uint32 length )
{
 bufLen   = length;
 gapLen   = 0;
 selStart = 0;
 selEnd   = 0;
 curPtr   = 0;
 drawPtr  = 0;
 modified = False;
 IsStatusLineOn=False;
 IsFoundOn=False;
 IsHLCOn=False;

 uint32 lines   = 0,
        maxLen  = 0;  // To know how large must be the edition buffer
 //buffer[length] = 0;

 unsigned conta;
 for (conta=0; conta<length; conta++)
    {
     if (buffer[conta]=='\r')
       {
        conta++;
        if (conta==length)
          {
           setBufSize(length+1);
           bufLen++; length++;
           buffer[conta]='\n';
          }
        else
          if (buffer[conta]!='\n')
            {
             setBufSize(length+1);
             bufLen++; length++;
             memmove(buffer+conta+1,buffer+conta,length-conta);
             buffer[conta]='\n';
            }
       }
#if 0
/* That's realy not needed, because the check is done (at least
   for DJGPP) in TCFileEditor::loadFile and as second this methode
   is absolutely slooooowwwwww
*/
     else
       if (buffer[conta]=='\n')
         {
          conta++;
          if (conta==length)
            {
             setBufSize(length+1);
             bufLen++; length++;
             buffer[conta-1]='\r';
             buffer[conta]='\n';
            }
          else
            {
             setBufSize(length+1);
             bufLen++; length++;
             memmove(buffer+conta,buffer+conta-1,length-conta+1);
             buffer[conta-1]='\r';
            }
         }
#endif
    }


 if (bufLen)
   {
    char *s=buffer,*end=s+bufLen;
    uint32 ThisLine;
    uint16 Attr=0;

    while (s<end)
      {
       ThisLine=LineMeassure(s,end,Attr);
       if (ThisLine)
         {
	  lenLines.setAll(lines++,ThisLine,Attr);
          if (ThisLine>maxLen)
             maxLen=ThisLine;
         }
       s+=ThisLine;
      }
   }
 else
    lenLines.setAll(0,0,0);
 drawLine=0;            // First displayed line
 totalLines=lines ? lines-1 : 0;    // Total number of lines
 limit.y = lines;
 lineInEdition=0;       // Line number in edition process
 IslineInEdition=False; // There is a line under edition?
 curLinePtr=buffer;     // Pointer to the start of the line under the cursor
 delta.x = 0;
 delta.y = 0;           // Origin in window
 curPos = delta;        // Origin in file
 ForceSelection = 0;

 // Allocate the Edition buffer
 if (bufEdit && (maxLen>bufEditLen))
   {
    delete bufEdit;
    bufEdit=0;
   }
 limit.x=max(maxLen,MinLineLen);
 if (!bufEdit)
   {
    bufEditLen=limit.x;
    bufEdit=new char[bufEditLen+4];
   }

 selLineStart=selLineEnd=selNewStart=selNewEnd=0;
 selHided=False;         // Hide the selection
 NotExpandingMacro=True;
 memset((void *)Markers,0,10*sizeof(uint32)); // Clean the markers

 // Initialize the undo thing.
 UndoArray[0].Type=UndoSt=undoNoUndo;
 UndoBase=UndoActual=UndoTop=0;
 undoLockCount=undoGroupCount=0;
 UndoArray[0].X=UndoArray[0].Y=0;

 // Initialize the rect. sel
 Xr1=Yr1=Xr2=Yr2=0;
 selRectHided=True;
 selRectClip=NULL;

 update(ufView);
 return;
}

/****************************************************************************

   Function: Boolean setBufSize( uint32 newSize )

   Type: TCEditor member.

   Objetive: Set the size of the buffer, but not allocate the memory, this
   task is made by a child class in the hierarchy (FileEditor).
     Is virtual of course.

   Parameters:
   newSize: obvious.

   Return:
   True if there is enough space.

   From Borland's TV 1.03.

****************************************************************************/

Boolean TCEditor::setBufSize( uint32 newSize )
{
 return (newSize <= bufSize) ? True : False;
}

/****************************************************************************

   Function: void setCmdState( uint16 command, Boolean enable )

   Type: TCEditor member.

   Objetive:
     Enables or disables the given command depending on whether enable is True
   or False and whether the editor is sfActive.
     The command is always disabled if the editor is not the selected view.
     Offers a convenient alternative to enableCommands and disableCommands.

   Parameters:
   command: The selected command (Copy, Paste, etc).
   enable: The new state.

   by Robert.

****************************************************************************/

void TCEditor::setCmdState( uint16 command, Boolean enable )
{
 if ( enable && (state & sfActive) != 0 )
    enableCommand(command);
 else
    disableCommand(command);
}


/****************************************************************************

   Function: void setSelect( uint32 newStart, uint32 newEnd,
                             Boolean curStart )

   Type: TCEditor member.

   Objetive:
     Sets the selection to the given offsets into the file, and redraws the
   view as needed.
     This member function will either place the cursor in front of or behind
   the selection, depending on the value (True or False, respectively) of
   curStart.

   by SET.

****************************************************************************/

void TCEditor::setSelect( uint32 newStart, uint32 newEnd, Boolean curStart )
{
 uint32 p;
 if ( curStart != 0 )
    p = newStart;
 else
    p = newEnd;

 uchar flags = ufUpdate;

 if ( newStart != selStart || newEnd != selEnd )
    if ( newStart != newEnd || selStart != selEnd )
       flags = ufView;

 if (p!=(uint32)(ColToPointer()-buffer))
    GotoOffSet(p);

 selStart = newStart;
 selEnd   = newEnd;
 selHided = False;
 update(flags);
}


/****************************************************************************

   Function: void setState( uint16 aState, Boolean enable )

   Type: TCEditor member.

   Objetive:
     Overrides TView::setState to hide and show the indicator and scroll bars.
     It first calls TView::setState to enable and disable commands. If you
   wish to enable and disable additional commands, override updateCommands
   instead.
     This is called whenever the command states should be updated.

   From Borland's TV 1.03.

****************************************************************************/

void TCEditor::setState( uint16 aState, Boolean enable )
{
 TView::setState(aState, enable);
 switch( aState )
     {
      case sfActive:
	  if( hScrollBar != 0 )
	      hScrollBar->setState(sfVisible, enable);
	  if( vScrollBar != 0 )
	      vScrollBar->setState(sfVisible, enable);
	  if( indicator != 0 )
	      indicator->setState(sfVisible, enable);
	  updateCommands();
	  break;

      case sfExposed:
	  if( enable )
	      unlock();
     }
}

/****************************************************************************

   Function: void startSelect()

   Type: TCEditor member.

   Objetive: Set the start of the selection, but doesn't do more. See
   SetStartOfSelecting.

   by SET.

****************************************************************************/

void TCEditor::startSelect()
{
 selStart=(uint32)(ColToPointer()-buffer);
}

/****************************************************************************

   Function: void toggleInsMode(Boolean allowUndo)

   Type: TCEditor member.

   Objetive: Toggle the insertion/overwrite mode.

   From Borland's TV 1.03 + SET Undo.

****************************************************************************/

void TCEditor::toggleInsMode(Boolean allowUndo)
{
 if (allowUndo)
    addToUndo(undoCutInMov);
 overwrite = (!overwrite) ? True : False;
 setState(sfCursorIns, (!getState(sfCursorIns)) ? True : False);
}


/****************************************************************************

   Function: void trackCursor( Boolean center )

   Type: TCEditor member.

   Objetive: Adjust the delta to make the cursor position visible.

   Parameter:
   center: True => keep the cursor in the middle of the screen in the y axe.

   Notes:
     Adapted to limit the cursor movement

   From Borland's TV 1.03.

****************************************************************************/

void TCEditor::trackCursor( Boolean center )
{
 int x=curPos.x;

 if (x>=MaxLineLen)
   {
    Beep();
    curPos.x=x=MaxLineLen-1;
   }
 if (x>=limit.x)
    limit.x=x+1;

 if ( center )
    scrollTo( x - size.x + 1, curPos.y - size.y / 2);
 else
    scrollTo( max(x - size.x + 1, min(delta.x, x)),
	      max(curPos.y - size.y + 1, min(delta.y, curPos.y)));
}

/****************************************************************************

   Function: void unlock()

   Type: TCEditor member.

   Objetive: Unlock the draw system and force an adecuated redraw.

   From Borland's TV 1.03.

****************************************************************************/

void TCEditor::unlock()
{
 if ( lockCount > 0 )
   {
    lockCount--;
    if ( lockCount == 0 )
	doUpdate();
   }
}

/****************************************************************************

   Function: void update( uchar aFlags )

   Type: TCEditor member.

   Objetive: Set the draw flags to the desired value, and make a redraw if
   the editor is unlocked.

   Parameter:
   aFlags: flags to activate.

   From Borland's TV 1.03.

****************************************************************************/

void TCEditor::update( uchar aFlags )
{
 updateFlags |= aFlags;
 if ( lockCount == 0 )
    doUpdate();
}

/****************************************************************************

   Function: void updateCommands()

   Type: TCEditor member.

   Objetive:
     Called whenever the commands should be updated. This is used to
   enable and disable commands such as cmUndo, cmClip, and cmCopy.

   by SET

****************************************************************************/

void TCEditor::updateCommands()
{
 setCmdState( cmcUndo, ( UndoActual!=UndoBase ) ? True : False );
 setCmdState( cmcRedo, ( UndoActual<UndoTop ) ? True : False );

 Boolean hs=hasSelection();
 if ( !isClipboard() )
   {
    setCmdState(cmcCut, hs);
    setCmdState(cmcCopy, hs);
    setCmdState(cmcPaste,
		(clipboard != 0 && (clipboard->hasSelection())) ? True : False );
   }
 setCmdState(cmcClear, hs);
 setCmdState(cmcFind, True);
 setCmdState(cmcReplace, True);
 setCmdState(cmcSearchAgain, True);

 // For rectangular selections:
 Boolean rs=hasRectSel();
 setCmdState(cmcSelRectCopy,rs);
 setCmdState(cmcSelRectDel,rs);
 setCmdState(cmcSelRectMove,rs);
 setCmdState(cmcSelRectCut,rs);
 setCmdState(cmcSelRectPaste,Boolean(selRectClip!=NULL));
}


/****************************************************************************

   Function: void MoveCursorTo(uint32 x, uint32 y)

   Type: TCEditor member.

   Objetive: Move the cursor to the x,y coordinate.

   Parameter:
   x,y: new cursor position.

   by SET.

****************************************************************************/

void TCEditor::MoveCursorTo(uint32 x, uint32 y)
{
 if (y<(uint32)curPos.y)
    MoveLinesUp(curPos.y-y);
 else
    if (y>(uint32)curPos.y)
       MoveLinesDown(y-curPos.y);
 curPos.x=x;
}

/****************************************************************************

   Function: void RecalculateLineAttributes(void)

   Type: TCEditor member.

   Objetive: Recalculates the syntax highlight attributes of each line in
   the editor. Called by SetHighlightTo when there is a change in the
   syntax highlight system.

   by SET.

****************************************************************************/

void TCEditor::RecalculateLineAttributes(void)
{
 uint32 lines=0;

 if (bufLen)
   {
    char *s=buffer,*end=s+bufLen;
    uint32 ThisLine;
    uint16 Attr=0;

    while (s<end)
      {
       ThisLine=LineMeassure(s,end,Attr);
       if (ThisLine)
	  lenLines.setAll(lines++,ThisLine,Attr);
       s+=ThisLine;
      }
   }
}

/****************************************************************************

   Function: void SetHighlightTo(shlState sHL)

   Type: TCEditor member.

   Objetive: Set the selected syntax highlighy mode

   by SET.

****************************************************************************/

void TCEditor::SetHighlightTo(shlState sHL)
{
 switch (sHL)
   {
    case shlNoSyntax:
         TurnOffHighLight();
         break;
    case shlCSyntax:
         TurnOnCHighLight();
         if (LineMeassure!=LineMeassureC)
           {
            LineMeassure=LineMeassureC;
            RecalculateLineAttributes();
           }
         break;
    case shlPascalSyntax:
         TurnOnPascalHighLight();
         if (LineMeassure!=LineMeassurePascal)
           {
            LineMeassure=LineMeassurePascal;
            RecalculateLineAttributes();
           }
         break;
    case shlClipperSyntax:
         TurnOnClipperHighLight();
         if (LineMeassure!=LineMeassureClipper)
           {
            LineMeassure=LineMeassureClipper;
            RecalculateLineAttributes();
           }
         break;
    default: messageBox(_("Unhandled syntax highlight"),mfError | mfOKButton);
   }
}

/****************************************************************************

   Function: void write( opstream& os )

   Type: TCEditor member.

   Objetive: Write the asociated data to the class.

   From Borland's TV 1.03.
   Modified by Robert to be compatible with RHIDE.

****************************************************************************/

void TCEditor::write( opstream& os )
{
 TView::write( os );
 os << (unsigned)TCEDITOR_VERSION << hScrollBar << vScrollBar << indicator
#if defined( RHIDE ) // RHIDE uses a short, not an int
    << bufSize << (short)canUndo;
#else
    << bufSize << (int)canUndo;
#endif
}

/****************************************************************************

   Function: void read( ipstream& is )

   Type: TCEditor member.

   Objetive: Read the asociated data to the class.

   From Borland's TV 1.03.
   Modified by Robert to be compatible with RHIDE, plus some initializations.

****************************************************************************/

void *TCEditor::read( ipstream& is )
{
 TView::read( is );
#if defined( RHIDE ) // RHIDE uses a short, not an int
 short temp;
#else
 int temp;
#endif

 is >> LoadingVersion >> hScrollBar >> vScrollBar >> indicator
    >> bufSize >> temp;
 canUndo = (temp) ? True : False;
 selecting = False;
 overwrite = False;
 autoIndent = False;
 keyState = 0;
 initBuffer();
 if ( buffer != 0 )
    isValid = True;
 else
    {
     TCEditor::editorDialog( edOutOfMemory, 0 );
     bufSize = 0;
    }
 lockCount = 0;
 //lock();
 bufEdit = NULL; // must be initialized before setBufLen()
 bufEditLen = 0;
 MacroCount = 0;
 Recording  = False;
 TurnOffHighLight(); // Here only to ensure that the functions pointers are
                     // pointing to some valid place, the TCFileEditor::read
 LineMeassure=LineMeassureC; // must adjust these values
 setBufLen( 0 );

 // Initialize the mode of edition, that's temporal and optional
 UseTabs=staticUseTabs;          // Don't put Tabs, indent
 autoIndent=staticAutoIndent;
 intelIndent=staticIntelIndent;
 tabSize=staticTabSize;
 PersistentBlocks=staticPersistentBlocks;
 CrossCursorInCol=staticCrossCursorInCol;
 CrossCursorInRow=staticCrossCursorInRow;
 CrossCurInCacheC=CrossCurInCacheR=False;
 TransparentSel=staticTransparentSel;
 OptimalFill=staticOptimalFill;

 SpecialLines=NULL;

 return this;
}

TStreamable *TCEditor::build()
{
 return new TCEditor( streamableInit );
}

TCEditor::TCEditor( StreamableInit ) : TViewPlus( streamableInit )
{
}


/****************************************************************************

   Function: void GotoOffSet(uint32 o)

   Type: TCEditor member.

   Objetive: Move the cursor position to an offset in the buffer.

   Parameter:
   o: destination offset.

   by SET.

****************************************************************************/

void TCEditor::GotoOffSet(uint32 o)
{
 uint32 Acu=0;
 uint32 y=0;
 char *s;

 if (o>bufLen) return;

 for (;y<totalLines && Acu<o; y++)
     Acu+=lenLines[y];

 if (Acu>o)
    Acu-=lenLines[--y];
 curPos.y=y;
 s=curLinePtr=buffer+Acu;
 Acu=o-Acu;
 for (curPos.x=0; Acu; --Acu,s++)
     { AdvanceWithTab(*s,curPos.x); }
}

/****************************************************************************

   Function: void IndentBlock(uint32 Amount, char Fill, Boolean allowUndo)

   Type: TCEditor member.

   Objetive: indent a block.
   If Amount==0 indents to the first hole of the previous line.

   Parameter:
   Amount: number of chars to insert in each line.
   Fill: the character to insert (' ' or tab).
   allowUndo: if the operation is recorded in the undo array.

   by SET.

****************************************************************************/

void TCEditor::IndentBlock(uint32 Amount, char Fill, Boolean allowUndo)
{
 if (hasSelection() && !selHided)
   {
    // This routing is pretty Waco:
    if (IslineInEdition)
       MakeEfectiveLineInEdition();

    if (allowUndo)
       addToUndo(undoPre1IndBlock,NULL);
    unsigned Pos=(unsigned)(curLinePtr-buffer);
    // It's the cursor in the first line of the selection?
    if (selStart<Pos || selStart>Pos+lenLines[curPos.y])
      { // Nop
       GotoOffSet(selStart);
       if (curPos.y<delta.y)
         {
          trackCursor(True);
          AdjustDrawPtr();
         }
      }

    // Force this to avoid a little thing
    Pos=(unsigned)(curLinePtr-buffer);
    selStart=Pos;

    if (Amount+Fill==0)
      {
       // That's an special case: Indent all the block taking as reference
       // the first line.
       Fill=' ';
       int Xact,X=0;
       char *s=curLinePtr;

       // Search the column of the first non-blank in the first line of the block
       for (Xact=curPos.x; *s!='\r' && *s!='\n' && isspace(*s); s++)
	   { AdvanceWithTab(*s,Xact); }
       if (curPos.y>0)
	 { // Search a hole in the last line
	  s=curLinePtr-lenLines[curPos.y-1];

	  do
	   {
	    for (;*s!='\r' && *s!='\n' && !isspace(*s); s++) // While letters
		{ AdvanceWithTab(*s,X); }
	    for (;*s!='\r' && *s!='\n' && isspace(*s); s++)  // While spaces
		{ AdvanceWithTab(*s,X); }
	   }
	  while (*s!='\r' && *s!='\n' && X<=Xact); // to a mayor X or the end of line
	  if (X>Xact)
	     Amount=X-Xact;
	  else
	     Amount=NextTabPos(Xact)-Xact;
	 }
       else
	 Amount=NextTabPos(Xact)-Xact;
      }

    // How many lines?
    unsigned Lines,PosAux,y;
    for (Lines=0,y=curPos.y,PosAux=Pos; PosAux<selEnd;)
       {
	PosAux+=lenLines[y++];
	Lines++;
       }

    // Now let's go, do the work.

    // 1) Insert Lines bytes
    // Is the buffer enough large?
    unsigned Total=Lines*Amount;
    if (bufSize<bufLen+Total)
       setBufSize(bufLen+Total);
    memmove(buffer+PosAux+Total,buffer+PosAux,bufLen-PosAux);

    // 2) Update the selection and Buffer Length
    selEnd+=Total;
    bufLen+=Total;

    if (allowUndo)
      {
       addToUndo(undoPre2IndBlock,&Amount);
       addToUndo(undoIndBlock,&Fill);
      }

    // 3) Move the lines
    unsigned Length=lenLines[--y];
    for (Pos=PosAux; Lines; --Lines)
       {
	Pos-=Length;
	// Hey! don't forget the Markers
	for (int i=0; i<10; i++)
	   {
	    if (Markers[i]>=Pos && Markers[i]<(Pos+Length))
	       Markers[i]+=Total;
	   }
	memmove(buffer+Pos+Total,buffer+Pos,Length);
	memset(buffer+Pos+Total-Amount,Fill,Amount);
	//buffer[Pos+Lines-1]=32;
	lenLines.set(y,Length+Amount);
	Length=lenLines[--y];
	Total-=Amount;
       }

    modified=True;

    update(ufView);
   }
}

/****************************************************************************

   Function: uint32 IsUnIndentable(char *buffer,uint32 Pos,uint32 Amount)

   Type: Static function.

   Objetive: Check if the line can be unIndented Amount bytes.

   Parameter:
   buffer: The buffer.
   Pos: The offset of the line in the buffer.
   Amount: The number of bytes to delete.

   Return:
   The quantity to unIndent (Amount if there is enough space or the maximun
   available).

   by SET.

****************************************************************************/

static uint32 IsUnIndentable(char *buffer,uint32 Pos,uint32 Amount)
{
 uint32 i;
 buffer+=Pos;
 for (i=0; i<Amount; i++,buffer++)
    {
     if (*buffer!=' ' && *buffer!=9)
	return i;
    }
 return Amount;
}

/****************************************************************************

   Function: void UnIndentBlock(uint32 Amount, Boolean allowUndo)

   Type: TCEditor member.

   Objetive: Unindent a block.
   If Amount==0 unindents to the first available start of block.

   Parameter:
   Amount: number of chars to delete in each line.
   allowUndo: if the operation is recorded in the undo array.

   by SET.

****************************************************************************/

void TCEditor::UnIndentBlock(uint32 Amount, Boolean allowUndo)
{
 int i;
 UndoCell un;

 if (hasSelection() && !selHided)
   {
    if (IslineInEdition)
       MakeEfectiveLineInEdition();

    if (allowUndo)
      {
       addToUndo(undoPreCopyInfo);
       UndoSaveStartState(un);
       un.Type=undoUnIndBlock;
      }

    unsigned Pos=(unsigned)(curLinePtr-buffer);
    // It's the cursor in the first line of the selection?
    if (selStart<Pos || selStart>Pos+lenLines[curPos.y])
      { // Nop
       GotoOffSet(selStart);
       if (curPos.y<delta.y)
         {
          trackCursor(True);
          AdjustDrawPtr();
         }
      }

    // Force this to avoid a little thing
    Pos=(unsigned)(curLinePtr-buffer);
    selStart=Pos;
    un.selStart=Pos;

    if (Amount==0)
      { // That's an special case: UnIndent the block using the first line as
	// reference.
	char *s=curLinePtr,*p;
	int Y,X,Xact;

	// Search the column of the first non-blank in the first line of the block
	for (Xact=curPos.x; *s!='\r' && *s!='\n' && isspace(*s); s++)
	    { AdvanceWithTab(*s,Xact); }
	s=curLinePtr;
	X=Xact;
	Y=curPos.y;
	while (Y && X>=Xact)
	  {
	   s-=lenLines[--Y];
	   for (p=s,X=0; *p!='\r' && *s!='\n' && isspace(*p) && X<Xact; p++)
	       { AdvanceWithTab(*p,X); }
	  }
	if (X>=Xact)
	   Amount=Xact;
	else
	   Amount=Xact-X;
      }
    // If still in 0 => nothing to do
    if (Amount==0)
       return;
    modified=True;

    unsigned Length=selEnd-selStart;
    char *buf=new char[Length+sizeof(uint32)];
    if (buf==NULL) return;
    memcpy(buf+sizeof(uint32),buffer+selStart,Length);
    *(uint32 *)buf=Amount;
    un.Length=Length;
    un.s=buf;

    // Now let's go, do the work.
    unsigned PosAux,y;
    unsigned Eated=0;
    unsigned bytesToEat;
    for (y=curPos.y, PosAux=Pos; Pos<selEnd; ++y)
       {
	Length=lenLines[y];
	// Is UnIndentable?
	if ((bytesToEat=IsUnIndentable(buffer,Pos,Amount))!=0)
	  { // Move plus del
	   // Adjust the Markers
	   for (i=0; i<10; i++)
	      {
	       if (Markers[i]>Pos && Markers[i]<(Pos+Length))
		  Markers[i]-=(Eated+bytesToEat);
	       else if (Markers[i]==Pos)
		       Markers[i]-=Eated;
	      }
	   Eated+=bytesToEat;
	   Length-=bytesToEat;
	   memmove(buffer+PosAux,buffer+Pos+bytesToEat,Length);
	   lenLines.set(y,Length);
	   Pos+=bytesToEat;
	  }
	else
	  { // Only Move
	   memmove(buffer+PosAux,buffer+Pos,Length);
	   // Adjust the Markers
	   for (i=0; i<10; i++)
	      {
	       if (Markers[i]>=Pos && Markers[i]<(Pos+Length))
		  Markers[i]-=Eated;
	      }
	  }
	PosAux+=Length;
	Pos+=Length;
       }
    if (Eated)
      {
       memcpy(buffer+PosAux,buffer+PosAux+Eated,bufLen-(PosAux+Eated));
       bufLen-=Eated;
       selEnd-=Eated;
      }

    if (allowUndo)
      {
       UndoSaveFinalState(un);
       addToUndo(undoPostCopyInfo,&un);
      }

    update(ufView);
   }
}


/****************************************************************************

   Function: void RecalculateXofLineInEdit(void)

   Type: TCEditor member.

   Objetive: Calculate the X position based on the inEditPtr pointer.
     This routine should be called only when the line is under edition and you
   need to recalculate the X position.
     Called by BackSpace and Delete when the user deletes a Tab.

   by SET.

****************************************************************************/

void TCEditor::RecalculateXofLineInEdit(void)
{
 char *s=bufEdit;
 int X=0;
 while (s!=inEditPtr)
   {
    AdvanceWithTab(*s,X);
    s++;
   }
 curPos.x=X;
}


/****************************************************************************

   Function: void BackSpace(Boolean allowUndo)

   Type: TCEditor member.

   Objetive: Just the action for the backspace key.

   by SET.

****************************************************************************/

void TCEditor::BackSpace(Boolean allowUndo)
{
 int WidthFirstChar;

 if (!PersistentBlocks && hasSelection())
   {
    clipCut();
    return;
   }
 WidthFirstChar = ((IslineInEdition ? *bufEdit : *curLinePtr)=='\t') ? tabSize : 1;
 if (curPos.x<WidthFirstChar) // Is the first char in the line
   {
    if (curLinePtr!=buffer)
      {
       if (IslineInEdition)
	  MakeEfectiveLineInEdition();
       char *tmp = curLinePtr-1;
       if (tmp > buffer && *(tmp-1) == '\r') tmp--;
       deleteRange(tmp,curLinePtr,allowUndo);
      }
   }
 else
   {
    if (!IslineInEdition)
      {
       EditLine();
       if (!IslineInEdition)
          return;
      }
    uint32 PosOfIns=(uint32)(inEditPtr-bufEdit);
    if (!UseTabs && IsFirstCharInLine())
      { // UnIndent
       char *s=curLinePtr,*p;
       int Y,X,Xact;
       UndoDestroy temp=destBack;

       // The undo is very complex because the routine can replace tabs
       // with spaces and is imposible to reconstruct if we don't save
       // a total copy of the line.
       if (allowUndo)
          addToUndo(undoDestroyLine,(void *)&temp);
       X=Xact=curPos.x;
       Y=curPos.y;
       while (Y && X>=Xact)
	 {
	  s-=lenLines[--Y];
          if (*s=='\r' || *s=='\n')
             X=Xact;   // if is an empty line force to ignore it
          else
	     for (p=s,X=0; *p!='\r' && *p!='\n' && isspace(*p) && X<Xact; p++)
	         { AdvanceWithTab(*p,X); }
	 }
       if (X>=Xact)
	  X=0;
       //if (X>(inEditPtr-bufEdit))
       memmove(bufEdit+X,inEditPtr,restCharsInLine+1);
       memset(bufEdit,32,X);

       int dif=X-(int)PosOfIns;
       AdjustLineSel(PosOfIns,dif,True);

       // Update the markers
       for (int i=0; i<10; i++)
	  {
	   int Pos=MarkersInLine[i];
	   if (Pos>=0)
	     {
	      if ((unsigned)Pos>=PosOfIns)
		 MarkersInLine[i]+=dif;
	      else if (Pos>=X)
		      MarkersInLine[i]=X;
	     }
	  }

       inEditPtr=bufEdit+X;
       curPos.x=X;
      }
    else
      {
       if (allowUndo)
          addToUndo(undoDelChar,inEditPtr-1);
       // If one of the 2 chars is a tab the X must be recalculated
       int wasATab=*(inEditPtr-1)=='\t' || *inEditPtr=='\t';
       memcpy(inEditPtr-1,inEditPtr,restCharsInLine+1);
       AdjustLineSel((uint32)(inEditPtr-bufEdit),-1,True);

       // Update the markers
       for (int i=0; i<10; i++)
	  {
	   int Pos=MarkersInLine[i];
	   if (Pos>=0 && (unsigned)Pos>=PosOfIns)
	      MarkersInLine[i]--;
	  }
       inEditPtr--;
       if (wasATab)
          RecalculateXofLineInEdit();
       else
          curPos.x--;
      }
    modified=True;
    update(ufLine);
   }
 if (curPos.x<delta.x)
   {
    if (delta.x>7)
       delta.x-=8;
    else
       delta.x=0;
    update(ufView);
   }
}

// The following are defined for compatibility

/****************************************************************************

   Function: unsigned nextChar(unsigned p)

   Type: TCEditor member.

   Objetive: Return the offset of the next char in the buffer.
   Skips the \xA and checks the end of the buffer.

   Parameter:
   The actual position.

   by SET.

****************************************************************************/

unsigned TCEditor::nextChar(unsigned p)
{
 if (p==bufLen) return p;
 p++;
 if (p==bufLen) return p;
 if (buffer[p] == '\n' && buffer[p-1] == '\r') return (p+1);
 return p;
}

/****************************************************************************

   Function: unsigned prevChar(unsigned p)

   Type: TCEditor member.

   Objetive: Return the offset of the previous char in the buffer.
   Skips the \xA and checks the start of the buffer.

   Parameter:
   The actual position.

   by SET.

****************************************************************************/

unsigned TCEditor::prevChar(unsigned p)
{
  if (!p) return p;
  p--;
  if (!p) return p;
  if (buffer[p] == '\n' && buffer[p-1] == '\r') return (p-1);
  return p;
}


/****************************************************************************

   Function: unsigned lineEnd(unsigned p)

   Type: TCEditor member.

   Objetive: Return the offset of the end of the line.

   Parameter:
   The actual position.

   by Robert Hhne and adapted but not tested.

****************************************************************************/

unsigned TCEditor::lineEnd(unsigned p)
{
  unsigned di = p,cx,bx;
  unsigned curPtr=(unsigned)(ColToPointer()-buffer);
  bx = 0;
  cx = curPtr-di;
  if (cx<=0) goto lab1;
//  di += bx;
  while (cx--)
  {
    if (buffer[di++] == '\r') goto lab2;
    if (buffer[di-1] == '\n') goto lab2;
  }
  di = curPtr;
lab1:
  cx = bufLen;
  cx -= di;
  if (!cx) return di;
  //bx += gapLen;
  di += bx;
  while (cx--)
  {
    if (buffer[di++] == '\r') goto lab2;
    if (buffer[di-1] == '\n') goto lab2;
  }
  goto lab3;
lab2:
  di--;
lab3:
  di-=bx;
  return di;
}

/****************************************************************************

   Function: unsigned lineStart(unsigned p)

   Type: TCEditor member.

   Objetive: Return the offset of the start of the line.

   Parameter:
   The actual position.

   by Robert Hhne and adapted but not tested.

****************************************************************************/

unsigned TCEditor::lineStart(unsigned p)
{
  unsigned di = p,cx,bx;
  unsigned curPtr=(unsigned)(ColToPointer()-buffer);
  bx = 0;
  cx = di;
  cx -= curPtr;
  if (cx<=0) goto lab1;
  bx += gapLen;
  di += bx;
  di--;
  while (cx--)
  {
    if (buffer[di--] == '\r') goto lab2;
    if (buffer[di+1] == '\n') goto lab2;
  }
  bx -= gapLen;
  di = curPtr;
lab1:
  cx = di;
  if (!cx) goto lab4;
  di += bx;
  di--;
  while (cx--)
  {
    if (buffer[di--] == '\r') goto lab2;
    if (buffer[di+1] == '\n') goto lab2;
  }
  goto lab3;
lab2:
  di++;
  di++;
  di -= bx;
  if ((unsigned)di == curPtr) goto lab4;
  if ((unsigned)di == bufLen) goto lab4;
  if (buffer[di+bx] != '\n') goto lab4;
  di++;
  goto lab4;
lab3:
  di = 0;
lab4:
  return di;
}

/****************************************************************************

   Function: unsigned nextLine( unsigned p )

   Type: TCEditor member.

   Objetive: Return the offset of the start of the next line.

   Parameter:
   The actual position.

   From Borland's TV 1.03.

****************************************************************************/

unsigned TCEditor::nextLine( unsigned p )
{
 return nextChar(lineEnd(p));
}

/****************************************************************************

   Function: unsigned prevLine( unsigned p )

   Type: TCEditor member.

   Objetive: Return the offset of the start of the previous line.

   Parameter:
   The actual position.

   From Borland's TV 1.03.

****************************************************************************/

unsigned TCEditor::prevLine( unsigned p )
{
 return lineStart(prevChar(p));
}

/****************************************************************************

   Function: void setCurPtr( unsigned p, uchar selectMode )

   Type: TCEditor member.

   Objetive: Is the arcaic way to move the cursor, here only for
   compatibility

   Parameter:
   p: The new position.
   selectMode: to expand the selection if needed.

   From Borland's TV 1.03.

****************************************************************************/

void TCEditor::setCurPtr( unsigned p, uchar selectMode )
{
    unsigned anchor;
    if( (selectMode & smExtend) == 0 )
	anchor = p;
    else if( curPtr == selStart )
	anchor = selEnd;
    else
	anchor = selStart;

    if( p < anchor )
	{
	if( (selectMode & smDouble) != 0 )
	    {
	    p = prevLine(nextLine(p));
	    anchor = nextLine(prevLine(anchor));
	    }
	setSelect(p, anchor, True);
	}
    else
	{
	if( (selectMode & smDouble) != 0 )
	    {
	    p = nextLine(p);
	    anchor = prevLine(nextLine(anchor));
	    }
	setSelect(anchor, p, False);
	}
}


/****************************************************************************

   Function: void unlockUndo(void)

   Type: TCEditor member.

   Objetive: Manages the undoGroupCount variable to allow the undo grouping.

   by SET.

****************************************************************************/

void TCEditor::unlockUndo(void)
{
 if (undoLockCount>0)
   {
    undoLockCount--;
    if (!undoLockCount)
       undoGroupCount=0;
   }
}


/****************************************************************************

   Function: void undo()

   Type: TCEditor member.

   Objetive: Undoes some action.

   by SET.

****************************************************************************/

#define DecWithWrap(a,b) if (a) a--; else a=b-1
#define IncWithWrap(a,b) a++; if (a==b) a=0

void TCEditor::undo()
{
 if (UndoActual!=UndoBase)
   {
    int count=UndoArray[UndoActual].Count;
    do
      {
       undoOneAction();
      }
    while (count--);
   }
}

void TCEditor::undoOneAction()
{
 if (UndoActual!=UndoBase)
   {
    UndoCell &un=UndoArray[UndoActual];
    char *s;

    if (IslineInEdition)
       MakeEfectiveLineInEdition();

    // Is a change, first save the end parameters
    if (UndoSt!=undoNoUndo)
       UndoSaveFinalState(un);

    switch (un.Type)
      {
       case undoInMov:
            MoveCursorTo(un.X,un.Y);
            update(ufUpdate);
            break;

       case undoPutChar:
            {
             int d;
             char *s=ColToPointer(d);
             if (d<0)
               {
                if (-d<un.Length)
                   deleteRange(s-un.Length-d,s,False);
               }
             else
	        deleteRange(s-un.Length,s,False);
             EditLine();
            }
            //MoveCursorTo(un.X,un.Y);
            break;

       case undoOvrPutChar:
            MoveCursorTo(un.X,un.Y);
            if (overwrite!=(((un.Flags & undoOverWrite)!=0) ? True : False))
               toggleInsMode(False);
            EditLine();
            {
             int i;
             for (i=0; i<un.Length; i++)
                 InsertCharInLine(un.s2.s[i],False);
            }
            MoveCursorTo(un.X,un.Y);
            update(ufLine);
            break;

       case undoDelCharDel:
            insertBuffer( un.s, 0, un.Length, False, False, False );
            MoveCursorTo(un.X,un.Y);
            break;

       case undoDelChar:
            insertBuffer( un.s, 0, un.Length, False, False, False );
            MoveCursorTo(un.X,un.Y);
            break;

       case undoDelete:
            MoveCursorTo(un.Xf,un.Yf);
            insertBuffer(un.s,0,un.Length,False,False,False);
            MoveCursorTo(un.X,un.Y);
            break;

       case undoDeleteBuf:
            GotoOffSet(un.s2.OffSet);
            insertBuffer(un.s,0,un.Length,False,False,False);
            MoveCursorTo(un.X,un.Y);
            break;

       case undoInsert:
            MoveCursorTo(un.X,un.Y);
            s=ColToPointer();
            deleteRange(s,s+un.Length,False);
            if (un.s2.l)
               insertBuffer(un.s2.BufL->s,0,un.s2.BufL->len,False,False,True);
            break;

       case undoDestroyLine:
            MoveCursorTo(un.X,un.Y);
            deleteRange(curLinePtr,curLinePtr+LenWithoutCRLF(un.Y,curLinePtr),False);
            insertBuffer(un.s,0,un.Length,False,False,False);
            MoveCursorTo(un.X,un.Y);
            break;

       case undoIndBlockTab:
       case undoIndBlockSp:
            selStart=un.selStart;
            selEnd=un.selEnd;
            selHided=False;
            UnIndentBlock(un.Length,False);
            MoveCursorTo(un.X,un.Y);
            break;

       case undoUnIndBlock:
            deleteRange(buffer+un.selStartf,buffer+un.selEndf,False);
            insertBuffer(un.s,sizeof(uint32),un.Length,False,False,False);
            MoveCursorTo(un.X,un.Y);
            break;

       case undoToUpper:
       case undoToLower:
            deleteRange(buffer+un.selStartf,buffer+un.selEndf,False);
            insertBuffer(un.s,0,un.Length,False,False,False);
            MoveCursorTo(un.X,un.Y);
            break;

       case undoRectDel:
       case undoRectPaste:
            UndoRectangularPasteClear(un);
            break;

       case undoRectCopy:
            selRectClip=(struct selRecSt *)un.s;
            update(ufUpdate);
            break;

       case undoRectHide:
            selRectHided=Boolean(un.Length);
            update(ufView);
            break;

       case undoRectStart:
            {
             selRecSt *s=(selRecSt *)un.s;
             Xr1=s->Xr1;
             Yr1=s->Yr1;
             update(ufView);
            }
            break;

       case undoRectEnd:
            {
             selRecSt *s=(selRecSt *)un.s;
             Xr2=s->Xr2;
             Yr2=s->Yr2;
             update(ufView);
            }
            break;

       default:
            messageBox(_("Unhandled undo"),mfError | mfOKButton);
      }

    Boolean newBool=((un.Flags & undoModified)!=0) ? True : False;
    if (modified!=newBool)
      {
       modified=newBool;
       update(ufUpdate);
      }
    newBool=((un.Flags & undoSelHided)!=0) ? True : False;
    if (un.selStart!=selStart || un.selEnd!=selEnd || selHided!=newBool)
      {
       selStart=un.selStart;
       selEnd=un.selEnd;
       selHided=newBool;
       update(ufView);
      }
    if (IslineInEdition)
      {
       selNewStart=un.selStart;
       selNewEnd=un.selEnd;
      }
    if (overwrite!=((un.Flags & undoOverWrite)!=0) ? True : False)
       toggleInsMode(False);

    UndoSt=undoNoUndo;

    DecWithWrap(UndoActual,MAX_UNDO);
   }
}

/****************************************************************************

   Function: void redo(void)

   Type: TCEditor member.

   Objetive: Redoes an action.

   by SET.

****************************************************************************/

void TCEditor::redo(void)
{
 if (UndoActual!=UndoTop)
   {
    char *s;

    if (IslineInEdition)
       MakeEfectiveLineInEdition();

    IncWithWrap(UndoActual,MAX_UNDO);
    UndoSt=undoNoUndo;
    UndoCell &un=UndoArray[UndoActual];

    switch (un.Type)
      {
       case undoInMov:
            MoveCursorTo(un.Xf,un.Yf);
            update(ufUpdate);
            break;

       case undoPutChar:
            MoveCursorTo(un.X,un.Y);
            insertBuffer( un.s, 0, un.Length, False, False, False );
            break;

       case undoOvrPutChar:
            MoveCursorTo(un.X,un.Y);
            if (overwrite!=((un.Flags & undoOverWrite)!=0) ? True : False)
               toggleInsMode(False);
            EditLine();
            {
             int i;
             for (i=0; i<un.Length; i++)
                 InsertCharInLine(un.s[i],False);
            }
            update(ufLine);
            break;

       case undoDelCharDel:
            s=ColToPointer();
	    deleteRange(s,s+un.Length,False);
            break;

       case undoDelChar:
            s=ColToPointer();
	    deleteRange(s-un.Length,s,False);
            break;

       case undoDelete:
            MoveCursorTo(un.X,un.Y);
            s=ColToPointer();
            deleteRange(s,s+un.Length,False);
            MoveCursorTo(un.Xf,un.Yf);
            break;

       case undoDeleteBuf:
            s=buffer+un.s2.OffSet;
            deleteRange(s,s+un.Length,False);
            MoveCursorTo(un.Xf,un.Yf);
            break;

       case undoInsert:
            MoveCursorTo(un.X,un.Y);
            insertBuffer( un.s, 0, un.Length, False, False, False );
            MoveCursorTo(un.Xf,un.Yf);
            break;

       case undoDestroyLine:
            MoveCursorTo(un.X,un.Y);
            BackSpace(False);
            break;

       case undoIndBlockSp:
            selStart=un.selStart;
            selEnd=un.selEnd;
            selHided=False;
            IndentBlock(un.Length,' ',False);
            MoveCursorTo(un.Xf,un.Yf);
            break;

       case undoIndBlockTab:
            selStart=un.selStartf;
            selEnd=un.selEndf;
            selHided=False;
            IndentBlock(un.Length,9,False);
            MoveCursorTo(un.Xf,un.Yf);
            break;

       case undoUnIndBlock:
            UnIndentBlock(*((uint32 *)un.s),False);
            break;

       case undoToUpper:
            BlockToUpper(False);
            break;

       case undoToLower:
            BlockToLower(False);
            break;

       case undoRectDel:
            selRectDelete(Xr1,Yr1,Xr2,Yr2,False);
            break;

       case undoRectPaste:
            selRectPaste(selRectClip,curPos.x,curPos.y,False);
            break;

       case undoRectCopy:
            selRectClip=(struct selRecSt *)un.s2.s;
            update(ufUpdate);
            break;

       case undoRectHide:
            selRectHided=Boolean(!selRectHided);
            update(ufView);
            break;

       case undoRectStart:
            {
             selRecSt *s=(selRecSt *)un.s;
             Xr1=s->Xr2;
             Yr1=s->Yr2;
             update(ufView);
            }
            break;

       case undoRectEnd:
            {
             selRecSt *s=(selRecSt *)un.s;
             Xr2=s->Xr1;
             Yr2=s->Yr1;
             update(ufView);
            }
            break;

       default:
            messageBox(_("Unhandled redo"),mfError | mfOKButton);
      }

    Boolean newBool=((un.Flags & undoModifiedF)!=0) ? True : False;
    if (modified!=newBool)
      {
       modified=newBool;
       update(ufUpdate);
      }
    newBool=((un.Flags & undoSelHidedF)!=0) ? True : False;
    if (un.selStartf!=selStart || un.selEndf!=selEnd || selHided!=newBool)
      {
       selStart=un.selStartf;
       selEnd=un.selEndf;
       selHided=newBool;
       update(ufView);
      }
    if (overwrite!=(((un.Flags & undoOverWriteF)!=0) ? True : False))
       toggleInsMode(False);

    // Recall the function until we finish with the chain
    if (UndoActual!=UndoTop)
      {
       int aux=UndoActual;
       IncWithWrap(aux,MAX_UNDO);

       while (UndoArray[aux].Count)
         {
          redo();
          if (UndoActual==UndoTop) break;
          IncWithWrap(aux,MAX_UNDO);
         }
      }
   }
}



/****************************************************************************

   Function: void UndoSaveFinalState(UndoCell &un)

   Type: TCEditor member.

   Objetive: Fill the undo structure with the status of the editor at the
   end of the action.

   by SET.

****************************************************************************/

void TCEditor::UndoSaveFinalState(UndoCell &un)
{
 un.Xf=curPos.x;
 un.Yf=curPos.y;
 if (IslineInEdition)
   {
    un.selStartf=selNewStart;
    un.selEndf=selNewEnd;
   }
 else
   {
    un.selStartf=selStart;
    un.selEndf=selEnd;
   }
 if (selHided)  un.Flags|=undoSelHidedF;
 if (modified)  un.Flags|=undoModifiedF;
 if (overwrite) un.Flags|=undoOverWriteF;
}


/****************************************************************************

   Function: void UndoSaveStartState(UndoCell &un)

   Type: TCEditor member.

   Objetive: Fill the undo structure with the status of the editor at the
   start of the action.

   by SET.

****************************************************************************/

void TCEditor::UndoSaveStartState(UndoCell &un)
{
 un.X=curPos.x;
 un.Y=curPos.y;
 if (IslineInEdition)
   {
    un.selStart=selNewStart;
    un.selEnd=selNewEnd;
   }
 else
   {
    un.selStart=selStart;
    un.selEnd=selEnd;
   }
 un.Flags=0;
 if (selHided)  un.Flags|=undoSelHided;
 if (modified)  un.Flags|=undoModified;
 if (overwrite) un.Flags|=undoOverWrite;
}

/****************************************************************************

   Function: void addToUndo(UndoState st, void *p)

   Type: TCEditor member.

   Objetive: Add an action to the undo list.

   by SET.

****************************************************************************/

void TCEditor::addToUndo(UndoState st, void *p)
{
 unsigned cont;

 UndoCell &un=UndoArray[UndoActual];

 if (un.Count<=undoGroupCount)
 if (st==UndoSt)
   {
    switch (st) // Grouped things
      {
       case undoInMov: // The cursor mov is grouped
            return;
       // The chars inserted one by one are stored in one cell
       case undoDelCharDel:
       case undoPutChar:
            if (un.Length && !(un.Length%UNDO_CHARS_SIZE))
              {
               char *s=(char *)realloc(un.s,un.Length+UNDO_CHARS_SIZE);
               UndoArray[UndoActual].s=s;
               s[un.Length++]=*((char *)p);
               return;
              }
            un.s[un.Length++]=*((char *)p);
            return;

       case undoOvrPutChar:
            if (un.Length && !(un.Length%UNDO_CHARS_SIZE))
              {
               UndoArray[UndoActual].s=(char *)realloc(un.s,un.Length+UNDO_CHARS_SIZE);
               UndoArray[UndoActual].s2.s=(char *)realloc(un.s2.s,un.Length+UNDO_CHARS_SIZE);
               UndoArray[UndoActual].s[un.Length]=*((char *)p);
               UndoArray[UndoActual].s2.s[un.Length++]=*((char *)p+1);
               return;
              }
            un.s[un.Length]=*((char *)p);
            un.s2.s[un.Length++]=*((char *)p+1);
            return;

       // The same but in reverse order
       case undoDelChar:
            if (un.Length && !(un.Length%UNDO_CHARS_SIZE))
              {
               char *s=(char *)realloc(un.s,un.Length+UNDO_CHARS_SIZE);
               UndoArray[UndoActual].s=s;
               memmove(s+1,s,un.Length++);
               s[0]=*((char *)p);
               return;
              }
            memmove(un.s+1,un.s,un.Length++);
            un.s[0]=*((char *)p);
            return;

       // If he repeat the pre-delete info simply ingnore it, that's made to
       // allow a preset of the data from some place different to deleteRange.
       // BUT not the pointer.
       case undoPreDelete:
            un.s=(char *)p;
            un.s2.l=0;
            return;

       // Second time is the final X,Y
       //case undoDifSpaces:
       //     return;
       default:
            break;
      }
   }

 // undoToUpper undoToLower undoUnIndBlock undoRectPaste undoRectDel
 if (st==undoPostCopyInfo)
   {
    memcpy(&UndoArray[UndoActual],p,sizeof(UndoCell));
    return;
   }

 // First cames a predelete and then the delete
 if (st==undoDelete)
   {
    char *s=(char *)UndoArray[UndoActual].s;
    unsigned l=(unsigned)((char *)p-s);

    un.Length=l;
    un.s=new char[l];
    UndoSt=un.Type=st;
    memcpy(un.s,s,l);
    return;
   }

 // First cames a predelete and then the deletebuf
 if (st==undoDeleteBuf)
   {
    char *s=(char *)UndoArray[UndoActual].s;
    un.s2.OffSet=(unsigned)((char *)s-buffer); // Where to place the buffer

    unsigned l=(unsigned)((char *)p-s);
    un.Length=l;                // How many bytes

    un.s=new char[l];
    UndoSt=un.Type=st;
    memcpy(un.s,s,l);
    return;
   }

 // First cames a preinsert and then the insert
 if (st==undoInsert)
   {
    // A pointer to the data
    struct stUndoInsert *stI=(struct stUndoInsert *)p;

    uint32 l=un.Length=stI->l;
    un.s=new char[l];
    memcpy(un.s,stI->s,l);
    un.s2.BufL=stI->Eated;
    UndoSt=un.Type=st;
    return;
   }


 if (st==undoPre2IndBlock)
   {
    un.Length=*((uint32 *)p);
    return;
   }

 if (st==undoIndBlock)
   {
    char f=*((char *)p);
    UndoSt=un.Type= f==' ' ? undoIndBlockSp : undoIndBlockTab;
    return;
   }

 // Is a change, first save the end parameters first
 UndoSaveFinalState(un);

 // Increment the pointers
 IncWithWrap(UndoActual,MAX_UNDO);
 if (UndoActual==UndoBase)
   {
    do
      {
       freeUndoCell(UndoBase);
       IncWithWrap(UndoBase,MAX_UNDO);
      }
    while (UndoArray[UndoBase].Count && UndoActual!=UndoBase);
   }
 IncWithWrap(UndoTop,MAX_UNDO);
 while (UndoTop!=UndoActual)
   {
    DecWithWrap(UndoTop,MAX_UNDO);
    freeUndoCell(UndoTop);
   }

 UndoSt=st;
 UndoCell &un2=UndoArray[UndoActual];
 un2.Type=st;

 switch (st)
   {
    case undoPre1IndBlock:
    case undoInMov:
         UndoSaveStartState(un2);
         break;

    case undoOvrPutChar:
         un2.s2.s=new char[UNDO_CHARS_SIZE];
         un2.s2.s[0]=*((char *)p+1);
    case undoDelChar:
    case undoDelCharDel:
    case undoPutChar:
         un2.Length=1;
         un2.s=new char[UNDO_CHARS_SIZE];
         un2.s[0]=*((char *)p);
         UndoSaveStartState(un2);
         break;

    case undoRectCopy:
         un2.s=(char *)selRectClip;
         un2.s2.s=(char *)p;
         UndoSaveStartState(un2);
         break;

    case undoRectStart:
    case undoRectEnd:
    case undoPreDelete:
         un2.s=(char *)p;
         UndoSaveStartState(un2);
         break;

    case undoPreInsert:
         UndoSaveStartState(un2);
         break;

    // When we eat or put spaces like in the unindent in backspace
    /*
    case undoDifSpaces:
         un2.Length=*((int *)p);
         UndoSaveStartState(un2);
         break;*/

    // That's only to put a point between two movements
    case undoCutInMov:
         UndoSt=un2.Type=undoInMov;
         UndoSaveStartState(un2);
         break;

    case undoDestroyLine:
         cont=(unsigned)(inEditPtr-bufEdit+restCharsInLine);
         un2.Length=cont;
         un2.s=new char[cont+1];
         memcpy(un2.s,bufEdit,cont+1);
         UndoSaveStartState(un2);
         break;

    case undoRectHide:
         un.Length=(int)*((Boolean *)p);
         break;

    // That's used by the routines that handle the undo by itself
    case undoPreCopyInfo:
    default:
         break;
   }

 un2.Count=undoGroupCount;
 if (undoLockCount)
    undoGroupCount++;
}


/****************************************************************************

   Function: void freeUndoCell(int Index)

   Type: TCEditor member.

   UNDER CONSTRUCTION

   Objetive: Eliminates an undo cell in the list.

   by SET.

****************************************************************************/

void TCEditor::freeUndoCell(int Index)
{
 char *s;
 switch (UndoArray[Index].Type)
   {
    // This must free the allocated memory
    case undoOvrPutChar:
         s=UndoArray[Index].s2.s;
         if (s!=NULL)
            delete s;
    case undoPutChar:
    case undoDelChar:
    case undoDelCharDel:
    case undoDelete:
    case undoInsert:
    case undoUnIndBlock:
    case undoToUpper:
    case undoToLower:
    case undoRectPaste:
    case undoRectCopy:
    case undoRectDel:
    case undoRectStart:
    case undoRectEnd:
         s=UndoArray[Index].s;
         if (s!=NULL)
            delete s;
         break;
    default:
         break;
   }
}

void TCEditor::TurnOnCHighLight(void)
{
 if (TransparentSel)
    formatLinePtr=&TCEditor::formatLineHighLightTransparent;
 else
    formatLinePtr=&TCEditor::formatLineHighLight;
 SyntaxHL=shlCSyntax;
}

void TCEditor::TurnOnPascalHighLight(void)
{
 if (TransparentSel)
    formatLinePtr=&TCEditor::formatLineHighLightPascalTransparent;
 else
    formatLinePtr=&TCEditor::formatLineHighLightPascal;
 SyntaxHL=shlPascalSyntax;
}

void TCEditor::TurnOnClipperHighLight(void)
{
 if (TransparentSel)
    formatLinePtr=&TCEditor::formatLineHighLightClipperTransparent;
 else
    formatLinePtr=&TCEditor::formatLineHighLightClipper;
 SyntaxHL=shlClipperSyntax;
}

/****************************************************************************

   Function: uint16 defEditorDialog( int, ... )

   Type: Normal function.

   Objetive: Is the default function to handle the dialogs, the editor must
   define a real one.

   From Borland's TV 1.03.

****************************************************************************/

ushort defEditorDialog( int, ... )
{
 return cmCancel;
}

TEditorDialog  TCEditor::editorDialog = defEditorDialog;
unsigned TCEditor::editorFlags = efBackupFiles | efPromptOnReplace;
char  TCEditor::findStr[maxFindStrLen] = "";
char  TCEditor::replaceStr[maxReplaceStrLen] = "";
TCEditor *TCEditor::clipboard = 0;
int      TCEditor::colorsCached = 0;
unsigned TCEditor::staticTabSize = 3;
Boolean  TCEditor::staticUseTabs=False;
Boolean  TCEditor::staticAutoIndent=True;
Boolean  TCEditor::staticIntelIndent=False;
Boolean  TCEditor::staticPersistentBlocks=True;
unsigned TCEditor::LoadingVersion;
Boolean  TCEditor::staticCrossCursorInRow=False;
Boolean  TCEditor::staticCrossCursorInCol=False;
Boolean  TCEditor::staticShowMatchPair=False;
Boolean  TCEditor::staticTransparentSel=False;
Boolean  TCEditor::staticOptimalFill=False;
ushort   TCEditor::SearchInSel=0;
ushort   TCEditor::FromWhere=0;
Boolean  TCEditor::staticNoMoveToEndPaste=False;
char TCEditor::StatusLine[setMaxScreenX*2];
#if !defined( RHIDE ) // in RHIDE this is defined in a separate file
const char * const TCEditor::name = "TCEditor";
#endif


