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

  This file is part of the:

  TCEditor class by SET, copyright (c) 1996.

    This files can be used by Robert Hhne for your RHIDE, any other use
  needs the permission of the author.
    This code is based on the original code of Robert Hhne.

  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

  Made:

   Added the table for comments and preprocessor.
   Search enhanced by my own fast engine 2.75 to 25 times faster depending on
  the case.
   Better floats highlight.
   Eliminated the in_string, in_char, in_cpp_comment and in_prep test.
   is_symbol uses a look up table.
   Eliminated the temporal copy of name (faster and safter).
   Modified the SetChar for a (char *)DrawBuffer[bufptr*2]=c much better
  option.

26/9
  Patch from Robert for:
  1) Kill a bug with the garbage at the end of a line, a test for <=0 was
     added.
  2) Get the colors instead of use fixed values, that's includes the assign
     for EDITOR.

28/9
  Added Pascal highlight, is very green by now.
  Added Clipper highlight, is even more green.

30/9
  Applied the second patch of Robert to support strings crossing lines.

17/10
  Added a new method to avoid unused warnings (by Robert).
  Corrected to support reserved words with '_'

28/10
  Corrected some stuff about the number of bytes filled in the drawbuffer.

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

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

#define Uses_TView
#define Uses_TStringCollection
//#include <tv.h> /*/Caca*/ klklk
#include <tv.h>

#define Uses_TCEditor
#include "ceditor.h"

#include <ctype.h>
#include <stdio.h>

#ifndef __GNUC__
//#define BCC_DEBUG
#endif
#ifdef BCC_DEBUG
#include <alloc.h>
#include <conio.h>
#include <stdlib.h>
#endif

inline
static int in_range(uint32 start,uint32 end,uint32 pos)
{
 //if (start >= end) return 0;
 if (pos >= start && pos < end) return 1;
 return 0;
}

void SyntaxFormatLine( TCEditor * editor,char *DrawBuf,uint32 LinePtr,int Width,
                       unsigned short Attr, unsigned );
void SyntaxFormatLinePascal( TCEditor * editor,char *DrawBuf,uint32 LinePtr,int Width,
                       int check_comment_1,int check_comment_2,unsigned lineLength);
void SyntaxFormatLineClipper( TCEditor * editor,char *DrawBuf,uint32 LinePtr,int Width,
                       int check_c_comment, unsigned );
void SyntaxFormatLineNoSel( TCEditor * editor,char *DrawBuf,uint32 LinePtr,int Width,
                       unsigned short Attr,unsigned lineLength);
void SyntaxFormatLinePascalNoSel( TCEditor * editor,char *DrawBuf,uint32 LinePtr,int Width,
                       int check_comment_1,int check_comment_2,unsigned lineLength);
void SyntaxFormatLineClipperNoSel( TCEditor * editor,char *DrawBuf,uint32 LinePtr,int Width,
                       int check_c_comment, unsigned );

#define CALL  if (!call10(buffer,(char *)DrawBuf,color,count,offset,LinePtr,Width,tabSize)) return
#define CALL2 if (!call10(buffer,(char *)DrawBuf,color,count,offset,LinePtr,Width,tabSize)) goto paint
#define CALL3 call30(buffer,(char *)DrawBuf,bufLen,LinePtr,Width,tabSize,color)
#define CALL4 call20(buffer,(char *)DrawBuf,bufLen,LinePtr,Width,tabSize,color)

static unsigned fl_bufptr;

#define fill_line(flag)\
{\
  int count = Width-offset;\
  if (count<=0) return flag;\
  offset+=count;\
  while (count--)\
    {\
     drawBuf[fl_bufptr] = ' ';\
     drawBuf[fl_bufptr+1] = color;  \
     fl_bufptr+=2;\
    }\
  return flag;\
}

#define SETCHAR(c)\
 {\
  drawBuf[fl_bufptr]=c;\
  drawBuf[fl_bufptr+1]=color;\
  fl_bufptr+=2;\
  offset++;\
 }


Boolean call10(char *buffer,char *drawBuf,char color,int cx,
               unsigned &offset, unsigned &lineptr,unsigned Width,
               unsigned tabSize)
{
  uchar c;
  long count = (long)cx - (long)lineptr;
  if (count<=0)
     return True;
  do {
    c = buffer[lineptr++];
    if ( !c || c == 0x0a || c == 0x0d || c == 0x09)
    {
      if (c == 0x09)
      {
        do
        {
          SETCHAR(' ');
	} while ((offset % tabSize) != 0);
      }
      else
      {
        fill_line(False);
      }
    }
    else SETCHAR(c);
    if (offset >= Width)
    {
      return False;
    }
    count--;
  } while (count>0);
  return True;
}

unsigned call20(char *buffer,char *drawBuf,int bytesAvail, unsigned lineptr,unsigned Width,
            unsigned tabSize,char color)
{
  uchar c;
  int count = bytesAvail - (int)lineptr;

  if (count<=0) return 0;
  unsigned offset=0;
  buffer+=lineptr;

  do
    {
     c = *buffer;
     buffer++;
     if (c=='\r' || !c || c=='\n') // !c is for the lines under edition where 0 is the end
       {
        int count = Width-offset;
        if (count<=0) return offset;
        while (count--)
          {
           *drawBuf=' ';
           *(drawBuf+1)=color;
           drawBuf+=2;
          }
        return Width;
       }
     if (c=='\t')
       {
        int tabCount=tabSize-(offset % tabSize);
        while (tabCount--)
         {
          *drawBuf=' ';
          drawBuf+=2;
          offset++;
         }
       }
     else
       {
        *drawBuf=c;
        drawBuf+=2;
        offset++;
       }
    if (offset >= Width)
       return offset;
    count--;
   }
 while (count>0);
 return offset;
}


unsigned call30(char *buffer,char *drawBuf,int bytesAvail, unsigned lineptr,unsigned Width,
            unsigned tabSize,char color)
{
  uchar c;
  int count = bytesAvail - (int)lineptr;

  if (count<=0) return 0;
  unsigned offset=0;
  buffer+=lineptr;

  do
    {
     c = *buffer;
     buffer++;
     if (c=='\r' || !c || c=='\n') // !c is for the lines under edition where 0 is the end
       {
        int count = Width-offset;
        if (count<=0) return offset;
        while (count--)
          {
           *drawBuf=' ';
           *(drawBuf+1)=color;
           drawBuf+=2;
          }
        return Width;
       }
     if (c=='\t')
       {
        int tabCount=tabSize-(offset % tabSize);
        while (tabCount--)
         {
          *drawBuf=' ';
          *(drawBuf+1)=color;
          drawBuf+=2;
          offset++;
         }
       }
     else
       {
        *drawBuf=c;
        *(drawBuf+1)=color;
        drawBuf+=2;
        offset++;
       }
    if (offset >= Width)
       return offset;
    count--;
   }
 while (count>0);
 return offset;
}

#define normalColor (Colors & 0xff)
#define selectColor (Colors >> 8)

/* Old function
void TCEditor::formatLine( void *DrawBuf,
			  unsigned LinePtr,
			  int Width,
			  unsigned short Colors
			)
{
  unsigned count,offset;
  char color;
  fl_bufptr = 0;
  offset = 0;


  if (selHided)
    {
     color = normalColor;
     count = bufLen;
     CALL;
    }

  if (selStart > LinePtr)
    {
     color = normalColor;
     count = selStart;
     CALL;
    }
  color = selectColor;
  count = selEnd;
  CALL;

  color = normalColor;
  count = bufLen;
  CALL;
  count = Width-offset;
  //if (count<=offset) return;
  //while (count--) ((ushort far *)(DrawBuf))[bufptr++] = (color << 8) | ' ';
  while (count--)
     {
      ((char *)(DrawBuf))[fl_bufptr]=' ';
      ((char *)(DrawBuf))[fl_bufptr+1]=color;
      fl_bufptr+=2;
     }
}
*/

// Moved here by Robert
static char *BUFFER;
static TCEditor *EDITOR;
static uint32 lineptr;

#ifdef CACHED_COLORS
/*
by Robert:

 Enable the following code if you know, what it does.

1. It caches the color attributes for the editor and brings
   a big speedup especially for the syntax highlight, because
   TView::getColor is slow and called very often.

2. The cached colors are valid only, if the final application
   does not change the colors. If it changes the colors, the
   application should set 'colors_cached' to zero.
   One possiblity for this is to use that global variable. An
   other thing would be to change the handleEvent method of the
   editor to handle to an colors_changed broadcast or something
   like that.

3. Enabling the cache brings a speedup of about 15%
   without caching:  about  87 lines/second
   with caching:     about 100 lines/second
*/

static unsigned char cached_colors[cNumColors];

void TCEditor::CacheColors()
{
 int i;
 for (i=1;i<cNumColors;i++)
     cached_colors[i] = getColor(i);
}

#define GetColor(a) cached_colors[a]

#else

#define GetColor EDITOR->getColor

#endif

#define NormalColor  GetColor(cNormal)
#define CommentColor GetColor(cComment)
#define PreproColor  GetColor(cPre)
#define StringColor  GetColor(cString)
#define CharColor    GetColor(cChar)
#define IlegalColor  GetColor(cIllegal)
#define ResColor     GetColor(cReserved)
#define UserColor    GetColor(cUser)
#define OctalColor   GetColor(cOctal)
#define IntColor     GetColor(cInteger)
#define FloatColor   GetColor(cFloat)
#define SymbolColor  GetColor(cSymbol)
#define Symbol2Color GetColor(cSymbol2)
#define HexColor     GetColor(cHex)

/*** Old values
#define NormalColor  0x1E
#define CommentColor 0x17
#define PreproColor  0x1A
#define SymbolColor  0x1F
#define Symbol2Color 0x1C

#define StringColor  0x1B
#define CharColor    0x1D

#define IlegalColor  0x2C
#define ResColor     0x12
#define UserColor    0x13
#define OctalColor   0x3F
#define IntColor     0x15
#define FloatColor   0x16
#define HexColor     0x2B
***/

#pragma argsused
void TCEditor::formatLine( void *DrawBuf,
			  unsigned LinePtr,
			  int Width,
			  unsigned short Colors,
                          unsigned , // lineLen
                          unsigned short Attr,
                          unsigned   // LineNo needed for RHIDE
			)
{
 unsigned offset;
 int count; // must be signed
 char color;
 fl_bufptr = 0;
 offset = 0;

 if (selHided)
   {
    color = normalColor;
    count = bufLen;
    CALL;
   }
 if (selStart > LinePtr)
   {
    color = normalColor;
    count = selStart;
    CALL;
   }
 color = selectColor;
 count = selEnd;
 CALL;

 color = normalColor;
 count = bufLen;
 CALL;

 count = Width-offset;
 // Bug corrected by Robert:
 if (count<=0) return; // This is the fix for the bug with the garbage at
                       // the end of the line
 while (count--)
    {
     ((char *)(DrawBuf))[fl_bufptr]=' ';
     ((char *)(DrawBuf))[fl_bufptr+1]=color;
     fl_bufptr+=2;
    }
}

void PaintPreproNoSel(unsigned offset,char *db,char *buffer,unsigned lineLen,
                      unsigned VisibleWidth,int tabSize)
{
 char col=PreproColor,c;
 int in_com,in_cpp_com,x=0;

 in_com=in_cpp_com=0;
 VisibleWidth<<=1;
 // adjust lineLen relative to offset
 lineLen += offset;
 do
  {
   c=buffer[offset++];
   x++;
   if (c=='\r' || c=='\n') break;
   if (in_com)
     {
      if (c=='*' && buffer[offset]=='/')
        {
         db[fl_bufptr++]=c;
         db[fl_bufptr++]=col;
         c=buffer[offset++];
         x++;
         db[fl_bufptr++]=c;
         db[fl_bufptr++]=col;
         c=buffer[offset++];
         x++;
         in_com=0;
         col=PreproColor;
         if (c=='\r' || c=='\n') break;
        }
     }
   else
     {
      if (!in_cpp_com)
        {
         if (c=='/')
           {
            if (buffer[offset]=='/')
              {
               in_cpp_com=1;
               in_com=0;
               col=CommentColor;
              }
            else
              if (buffer[offset]=='*')
                {
                 in_com=1;
                 col=CommentColor;
                 db[fl_bufptr++]=c;
                 db[fl_bufptr++]=col;
                 c=buffer[offset++];
                 x++;
                }
           }
        }
     }
   if (c==9)
     {
      x--;
      do
      {
       db[fl_bufptr++]=' ';
       db[fl_bufptr++]=col;
       x++;
      } while ((x%tabSize) != 0);
     }
   else
     {
      db[fl_bufptr++]=c;
      db[fl_bufptr++]=col;
     }
  }
 while (offset<lineLen && fl_bufptr<VisibleWidth);
}

#define PCorrectColOfPos in_range(start,end,offset-1) ? selCol : col

void PaintPreproSel(unsigned offset,char *db,char *buffer,unsigned lineLen,
                    unsigned VisibleWidth,char selCol, unsigned start, unsigned end,
                    int tabSize)
{
 char col,c;
 int in_com,in_cpp_com,x=0;

 col=PreproColor;
 in_com=in_cpp_com=0;
 VisibleWidth<<=1;
 // adjust lineLen relative to offset
 lineLen += offset;
 do
  {
   c=buffer[offset++];
   x++;
   if (c=='\r' || c=='\n') break;
   if (in_com)
     {
      if (c=='*' && buffer[offset]=='/')
        {
         db[fl_bufptr++]=c;
         db[fl_bufptr++]=PCorrectColOfPos;
         c=buffer[offset++];
         x++;
         db[fl_bufptr++]=c;
         db[fl_bufptr++]=PCorrectColOfPos;
         c=buffer[offset++];
         x++;
         in_com=0;
         col=PreproColor;
         if (c=='\r' || c=='\n') break;
        }
     }
   else
     {
      if (!in_cpp_com)
        {
         if (c=='/')
           {
            if (buffer[offset]=='/')
              {
               in_cpp_com=1;
               in_com=0;
               col=CommentColor;
              }
            else
              if (buffer[offset]=='*')
                {
                 in_com=1;
                 col=CommentColor;
                 db[fl_bufptr++]=c;
                 db[fl_bufptr++]=PCorrectColOfPos;
                 c=buffer[offset++];
                 x++;
                }
           }
        }
     }
   if (c==9)
     {
      x--;
      do
      {
       db[fl_bufptr++]=' ';
       db[fl_bufptr++]=PCorrectColOfPos;
       x++;
      } while ((x%tabSize) != 0);
     }
   else
     {
      db[fl_bufptr++]=c;
      db[fl_bufptr++]=PCorrectColOfPos;
     }
  }
 while (offset<lineLen && fl_bufptr<VisibleWidth);
}

#pragma argsused
void TCEditor::formatLineHighLight( void *DrawBuf,
			  unsigned LinePtr,
			  int Width,
			  unsigned short Colors,
                          unsigned lineLen,
                          unsigned short Attr,
                          unsigned // LineNo needed for RHIDE
			)
{
  unsigned offset;
  int count; // must be signed
  char color;
  unsigned lineStart=LinePtr;
  char *db=(char *)DrawBuf;
  EDITOR = this; // for the two functions above
  fl_bufptr = 0;
  offset = 0;

  if (!lineLen)
    {
     if (!selHided && selStart<=LinePtr && selEnd>LinePtr)
        color = selectColor;
     else
        color = normalColor;
     goto End;
    }

  if (selHided || selStart>=selEnd || selStart>lineLen+LinePtr || selEnd<=LinePtr)
    {
     // There isn't selection here
     if (Attr & InsideCom)
       { // All comented
        color = CommentColor;
        count = bufLen;
        CALL;
        goto End;
       }
     if (Attr & PartialCom)
       { // Partially comented
        if ((Attr & Prepro) && !(Attr & StartInCom))
          {
           PaintPreproNoSel(LinePtr,db,buffer,lineLen,Width,tabSize);
           offset=fl_bufptr>>1;
           color = normalColor;
           goto End;
          }
        goto Parsear;
       }
     if (Attr & Prepro)
       { // Preprocesor
        color = PreproColor;
        count = bufLen;
        CALL;
        goto End;
       }
     // Totally clean
     goto Parsear;
    }
  // That's the else
  if (selStart<=LinePtr && selEnd>lineLen+LinePtr)
    { // All selected
     color = selectColor;
     count = bufLen;
     CALL;
     goto End;
    }

  if ((Attr & Prepro) && !(Attr & (InsideCom | StartInCom)))
    { // Preprocessor with selection
     PaintPreproSel(LinePtr,db,buffer,lineLen,Width,selectColor,selStart,selEnd,
                    tabSize);
     offset=fl_bufptr>>1;
     if (selEnd>lineLen+LinePtr)
        color = selectColor;
     else
        color = normalColor;
     goto End;
    }

Parsear:
  if (selHided)
    {
     color = normalColor;
     count = bufLen;
     CALL2;
    }
  if (selStart > LinePtr)
    {
     color = normalColor;
     count = selStart;
     CALL2;
    }
  color = selectColor;
  count = selEnd;
  CALL2;

  color = normalColor;
  count = bufLen;
  CALL2;

paint:
  SyntaxFormatLine( this,(char *)DrawBuf,lineStart,Width,Attr,lineLen);
  //return;
End:
  //count = Width-(fl_bufptr>>1);
  count = Width-offset;
  if (count<=0)
    {
     if (count<-(int)(tabSize))
       {
        printf("Error (bug) in formatLine (%d)\n",count);
#ifdef __GNUC__
        abort();
#endif
       }
     return; // This is the fix for the bug with the garbage at
             // the end of the line
    }
  while (count--)
     {
      ((char *)(DrawBuf))[fl_bufptr]=' ';
      ((char *)(DrawBuf))[fl_bufptr+1]=color;
      fl_bufptr+=2;
     }
}


static void PaintSelectionTransparent(unsigned selStart,unsigned selEnd,unsigned lineStart,
                                      char *db,char oldColor,unsigned lineLen,char *buffer,
                                      unsigned tabSize,unsigned Width)
{
 unsigned offset;
 int count;
 char color;

 char *s=buffer+lineStart;  // Is a pointer to the char in the buffer
 char *ori=s;
 offset=0;                  // Is the X coordinate

 // Move s and offset to the start of the selection, calculate the length of
 // the selected area.
 count=selStart-lineStart;
 if (count>0)
   { // The start is inside the line
    while (count--)
      {
       AdvanceWithTab(*s,offset);
       s++;
      }
    count=selEnd-selStart;
   }
 else
    count=selEnd-lineStart;

 // Prepare the colors
 color = oldColor & 0xF0;   // Only the background
 char colFor = color >> 4;

 // Preapare a pointer in the buffer
 char *db2=db+((offset<<1)+1);

 // Adjust count
 int PaintAll;
 unsigned skiped=s-ori;
 if ((unsigned)count+skiped>lineLen)
   { // If the selection ends outside the line
    count=lineLen-skiped;
    PaintAll=1;
   }
 else
    PaintAll=0;

 // Paint the line
 while (count-- && offset<Width)
   {
    if (*s=='\t')
      {
       int tabcount = tabSize-(offset % tabSize);
       while (tabcount--)
         {
          *db2=oldColor;
          db2+=2;
          offset++;
         }
      }
    else
      {
       char colOri=(*db2 & 0x0F);
       if (colOri==colFor)
         *db2=((colOri+1) & 0x0F) | color; // Ops!, the same color!
       else
         *db2=colOri | color;
       db2+=2;
       offset++;
      }
    s++;
   }

 // Paint outside it, if needed.
 if (PaintAll)
    while (offset<(unsigned)Width)
      {
       *db2=oldColor;
       db2+=2;
       offset++;
      }
}

#define FillRestOfLine() \
 { \
  count = Width-offset;  \
  if (count>0)           \
    {                    \
     while (count--)     \
        {                \
         ((char *)(DrawBuf))[fl_bufptr]=' ';      \
         ((char *)(DrawBuf))[fl_bufptr+1]=color;  \
         fl_bufptr+=2;   \
        }                \
    }                    \
 }

void TCEditor::formatLineHighLightTransparent( void *DrawBuf,
			  unsigned LinePtr,
			  int Width,
			  unsigned short Colors,
                          unsigned lineLen,
                          unsigned short Attr,
                          unsigned
			)
{
  unsigned offset;
  int count;
  char color;
  unsigned lineStart=LinePtr;
  char *db=(char *)DrawBuf;
  EDITOR = this; // for the two functions above
  fl_bufptr = 0;
  offset = 0;

  if (!lineLen)
    { // If empty just fill it with spaces
     color = normalColor;
    }
  else
  if (Attr & InsideCom)
    { // All comented
     color = CommentColor;
     offset= CALL3;
     fl_bufptr=offset<<1;
    }
  else
  if ((Attr & PartialCom) && (Attr & Prepro) && !(Attr & StartInCom))
    { // Partially comented
     PaintPreproNoSel(LinePtr,db,buffer,lineLen,Width,tabSize);
     offset=fl_bufptr>>1;
     color = normalColor;
    }
  else
  if ((Attr & Prepro) && !(Attr & PartialCom))
    { // Preprocesor
     color = PreproColor;
     offset= CALL3;
     fl_bufptr=offset<<1;
    }
  else
    {
     color = normalColor;
     offset=CALL4;
     fl_bufptr=offset<<1;
     SyntaxFormatLineNoSel( this,(char *)DrawBuf,lineStart,Width,Attr,lineLen);
    }

  FillRestOfLine();

  // Now paint the selection OVER the buffer
  if (!selHided && selStart<selEnd && selStart<=lineLen+lineStart && selEnd>lineStart)
     PaintSelectionTransparent(selStart,selEnd,lineStart,db,selectColor,
                               lineLen,buffer,tabSize,Width);
}


#pragma argsused
void TCEditor::formatLineHighLightPascal( void *DrawBuf,
			  unsigned LinePtr,
			  int Width,
			  unsigned short Colors,
                          unsigned lineLen,
                          unsigned short Attr,
                          unsigned // LineNo needed for RHIDE
			)
{
  unsigned offset;
  int count; // must be signed
  char color;
  unsigned lineStart=LinePtr;
  EDITOR = this; // for the two functions above
  fl_bufptr = 0;
  offset = 0;

  if (!lineLen)
    {
     if (!selHided && selStart<=LinePtr && selEnd>LinePtr)
        color = selectColor;
     else
        color = normalColor;
     goto End;
    }

  if (selHided || selStart>=selEnd || selStart>lineLen+LinePtr || selEnd<LinePtr)
    {
     // There isn't selection here
     if (Attr & InsidePascalCom)
       { // All comented
        color = CommentColor;
        count = bufLen;
        CALL;
        goto End;
       }
     if (Attr & PartialCom)
       { // Partially comented
        if ((Attr & Prepro) && !(Attr & StartInCom))
          {
           PaintPreproNoSel(LinePtr,(char *)DrawBuf,buffer,lineLen,Width,tabSize);
           offset=fl_bufptr>>1;
           color = normalColor;
           goto End;
          }
        goto Parsear;
       }
     if (Attr & Prepro)
       { // Preprocesor
        color = PreproColor;
        count = bufLen;
        CALL;
        goto End;
       }
     // Totally clean
     goto Parsear;
    }
  // That's the else
  if (selStart<=LinePtr && selEnd>lineLen+LinePtr)
    { // All selected
     color = selectColor;
     count = bufLen;
     CALL;
     goto End;
    }

Parsear:
  if (selHided)
    {
     color = normalColor;
     count = bufLen;
     CALL2;
    }
  if (selStart > LinePtr)
    {
     color = normalColor;
     count = selStart;
     CALL2;
    }
  color = selectColor;
  count = selEnd;
  CALL2;

  color = normalColor;
  count = bufLen;
  CALL2;

paint:
  SyntaxFormatLinePascal( this,(char *)DrawBuf,lineStart,Width,
                          Attr & StartInCom,Attr & StartInCom2,lineLen);
  //return;
End:
  count = Width-offset;
  // Bug corrected by Robert:
  if (count<=0) return; // This is the fix for the bug with the garbage at
                        // the end of the line
  while (count--)
     {
      ((char *)(DrawBuf))[fl_bufptr]=' ';
      ((char *)(DrawBuf))[fl_bufptr+1]=color;
      fl_bufptr+=2;
     }
}


void TCEditor::formatLineHighLightPascalTransparent( void *DrawBuf,
			  unsigned LinePtr,
			  int Width,
			  unsigned short Colors,
                          unsigned lineLen,
                          unsigned short Attr,
                          unsigned
			)
{
  unsigned offset;
  int count;
  char color;
  unsigned lineStart=LinePtr;
  char *db=(char *)DrawBuf;
  EDITOR = this; // for the two functions above
  fl_bufptr = 0;
  offset = 0;

  if (!lineLen)
    { // If empty just fill it with spaces
     color = normalColor;
    }
  else
  if (Attr & InsidePascalCom)
    { // All comented
     color = CommentColor;
     offset= CALL3;
     fl_bufptr=offset<<1;
    }
  else
  if ((Attr & PartialCom) && (Attr & Prepro) && !(Attr & StartInCom))
    { // Partially comented
     PaintPreproNoSel(LinePtr,db,buffer,lineLen,Width,tabSize);
     offset=fl_bufptr>>1;
     color = normalColor;
    }
  else
  if ((Attr & Prepro) && !(Attr & PartialCom))
    { // Preprocesor
     color = PreproColor;
     offset= CALL3;
     fl_bufptr=offset<<1;
    }
  else
    {
     color = normalColor;
     offset=CALL4;
     fl_bufptr=offset<<1;
     SyntaxFormatLinePascalNoSel( this,(char *)DrawBuf,lineStart,Width,
                                  Attr & StartInCom,Attr & StartInCom2,lineLen);
    }

  FillRestOfLine();

  // Now paint the selection OVER the buffer
  if (!selHided && selStart<selEnd && selStart<=lineLen+lineStart && selEnd>lineStart)
     PaintSelectionTransparent(selStart,selEnd,lineStart,db,selectColor,
                               lineLen,buffer,tabSize,Width);
}


#pragma argsused
void TCEditor::formatLineHighLightClipper( void *DrawBuf,
			  unsigned LinePtr,
			  int Width,
			  unsigned short Colors,
                          unsigned lineLen,
                          unsigned short Attr,
                          unsigned // LineNo needed for RHIDE
			)
{
  unsigned offset;
  int count;
  char color;
  unsigned lineStart=LinePtr;
  char *db=(char *)DrawBuf;
  EDITOR = this; // for the two functions above
  fl_bufptr = 0;
  offset = 0;

  //Attr=lenLines.getAttr(line);
  //lineLen=lenLines[line];

  if (!lineLen)
    {
     if (!selHided && selStart<=LinePtr && selEnd>LinePtr)
        color = selectColor;
     else
        color = normalColor;
     goto End;
    }

  if (selHided || selStart>=selEnd || selStart>lineLen+LinePtr || selEnd<LinePtr)
    {
     // There isn't selection here
     if (Attr & InsideCom)
       { // All comented
        color = CommentColor;
        count = bufLen;
        CALL;
        goto End;
       }
     if (Attr & PartialCom)
       { // Partially comented
        if ((Attr & Prepro) && !(Attr & StartInCom))
          {
           PaintPreproNoSel(LinePtr,db,buffer,lineLen,Width,tabSize);
           offset=fl_bufptr>>1;
           color = normalColor;
           goto End;
          }
        goto Parsear;
       }
     if (Attr & Prepro)
       { // Preprocesor
        color = PreproColor;
        count = bufLen;
        CALL;
        goto End;
       }
     // Totally clean
     goto Parsear;
    }
  // That's the else
  if (selStart<=LinePtr && selEnd>lineLen+LinePtr)
    { // All selected
     color = selectColor;
     count = bufLen;
     CALL;
     goto End;
    }

  if ((Attr & Prepro) && !(Attr & (InsideCom | StartInCom)))
    { // Preprocessor with selection
     PaintPreproSel(LinePtr,db,buffer,lineLen,Width,selectColor,selStart,selEnd,
                    tabSize);
     offset=fl_bufptr>>1;
     if (selEnd>lineLen+LinePtr)
        color = selectColor;
     else
        color = normalColor;
     goto End;
    }

Parsear:
  if (selHided)
    {
     color = normalColor;
     count = bufLen;
     CALL2;
    }
  if (selStart > LinePtr)
    {
     color = normalColor;
     count = selStart;
     CALL2;
    }
  color = selectColor;
  count = selEnd;
  CALL2;

  color = normalColor;
  count = bufLen;
  CALL2;

paint:
  SyntaxFormatLineClipper( this,(char *)DrawBuf,lineStart,Width,Attr & StartInCom,lineLen);
  //return;
End:
  count = Width-offset;
  // Bug corrected by Robert:
  if (count<=0) return; // This is the fix for the bug with the garbage at
                        // the end of the line
  while (count--)
     {
      ((char *)(DrawBuf))[fl_bufptr]=' ';
      ((char *)(DrawBuf))[fl_bufptr+1]=color;
      fl_bufptr+=2;
     }
}

void TCEditor::formatLineHighLightClipperTransparent( void *DrawBuf,
			  unsigned LinePtr,
			  int Width,
			  unsigned short Colors,
                          unsigned lineLen,
                          unsigned short Attr,
                          unsigned
			)
{
  unsigned offset;
  int count;
  char color;
  unsigned lineStart=LinePtr;
  char *db=(char *)DrawBuf;
  EDITOR = this; // for the two functions above
  fl_bufptr = 0;
  offset = 0;

  if (!lineLen)
    { // If empty just fill it with spaces
     color = normalColor;
    }
  else
  if (Attr & InsideCom)
    { // All comented
     color = CommentColor;
     offset= CALL3;
     fl_bufptr=offset<<1;
    }
  else
  if ((Attr & PartialCom) && (Attr & Prepro) && !(Attr & StartInCom))
    { // Partially comented
     PaintPreproNoSel(LinePtr,db,buffer,lineLen,Width,tabSize);
     offset=fl_bufptr>>1;
     color = normalColor;
    }
  else
  if ((Attr & Prepro) && !(Attr & PartialCom))
    { // Preprocesor
     color = PreproColor;
     offset= CALL3;
     fl_bufptr=offset<<1;
    }
  else
    {
     color = normalColor;
     offset=CALL4;
     fl_bufptr=offset<<1;
     SyntaxFormatLineClipperNoSel( this,(char *)DrawBuf,lineStart,Width,Attr & StartInCom,lineLen);
    }

  FillRestOfLine();

  // Now paint the selection OVER the buffer
  if (!selHided && selStart<selEnd && selStart<=lineLen+lineStart && selEnd>lineStart)
     PaintSelectionTransparent(selStart,selEnd,lineStart,db,selectColor,
                               lineLen,buffer,tabSize,Width);
}

// For Reserved words
static char *RWfirstLetters=NULL;
static int *RWlenTable;
static int *RWfirstWithLength;
static char **RWmainTable;
static int *RWequalCharsInNext;
static int RWmaxLen=0;

// For User words
static char *UWfirstLetters=NULL;
static int *UWlenTable;
static int *UWfirstWithLength;
static char **UWmainTable;
static int *UWequalCharsInNext;
static int UWmaxLen=0;

// For Pascal Reserved words
static char *PRfirstLetters=NULL;
static int *PRlenTable;
static int *PRfirstWithLength;
static char **PRmainTable;
static int *PRequalCharsInNext;
static int PRmaxLen=0;

// For Clipper Reserved words
static char *CRfirstLetters=NULL;
static int *CRlenTable;
static int *CRfirstWithLength;
static char **CRmainTable;
static int *CRequalCharsInNext;
static int CRmaxLen=0;

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

  Function: SETSECreateTables

  Create the necesary tables for the search

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

static Boolean SETSECreateTables(char *&firstLetters,
                                 int *&lenTable,
                                 int *&firstWithLength,
                                 char **&mainTable,
                                 int *&equalCharsInNext,
                                 int &maxLen,
                                 TStrCol *TSC)
{
 int i;
 int total=TSC->getCount();
 int thisLen;
 maxLen=0;

 for (i=0; i<total; i++)
    {
     if ((thisLen=strlen((char *)TSC->at(i)))>maxLen)
        maxLen=thisLen;
    }

 // *:-P  One allocation for the five tables.
 firstLetters=new char[total*(sizeof(char)+sizeof(char *)+sizeof(int))+(2*sizeof(int))*(maxLen+1)];
 if (firstLetters==NULL)
    return False;
 lenTable=(int *)&firstLetters[total];
 firstWithLength=&lenTable[maxLen+1];
 mainTable=(char **)&firstWithLength[maxLen+1];
 equalCharsInNext=(int *)&mainTable[total];

 // Fill the length table
 for (i=0; i<=maxLen; i++)
    {
     firstWithLength[i]=0;
     lenTable[i]=0;
    }

 for (i=0; i<total; i++)
     lenTable[strlen((char *)TSC->at(i))]++;

 // Search & Clasify
 int pos=0;
 for (i=0; i<=maxLen; i++)
    {
     int j=0,n=0;
     while (j<lenTable[i])
       {
        char *s=(char *)TSC->at(n);
        if ((int)strlen(s)==i)
          {
           if (j==0)
              firstWithLength[i]=pos;
           mainTable[pos++]=s;
           j++;
          }
        n++;
       }
    }

 // Make the first letters
 for (i=0; i<total; i++)
     firstLetters[i]=mainTable[i][0];

 // Make the equality table
 for (pos=0,i=0; i<=maxLen; i++)
    {
     int j=lenTable[i];
     while (j)
       {
        if (j>1)
          {
           char *este=mainTable[pos];
           char *prox=mainTable[pos+1];
           int c;
           for (c=0; *este==*prox && *este; este++, prox++, c++);
           equalCharsInNext[pos]=c;
          }
        else
          equalCharsInNext[pos]=0;
        pos++;
        j--;
       }
    }
 return True;
}

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

  Function: SETSE_RW_Search

  Is the search engine of the SETSE algorithm.
  The tables are sorted 1st by string length and then by alphabetic order.
  When we need to search a string first we check if the length is valid, if
not the search ends, if the length is OK we go directly to the first element
with this length, then we use a table with the first letters of the list and
we search in this table until we found the letter or we exced the range of
word with the desired length ... puf ..., if we found a match we start to
compare the whole string, if the any letter fails we ask if the following
string have enough equal letters (there is a table for this) if not we return,
if yes we continue the comparison in the next string, not from the start the
start because we know that this string match the first letters.
  The goal of the system is: We never retrace in the string index we ever
advance or still in the same index.
  If you don't understand what I'm saying don't worry my english is a
disaster and the algorithm is a little tricky.

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

#define is_reserved(a,b)  SETSE_RW_Search(a,b)
static int SETSE_RW_Search(char *s, int l)
{
 // Is in the length range?
 if (l<=RWmaxLen)
   {
    int cant=RWlenTable[l];
    // Exist any of this length?
    if (cant)
      {
       // Take the pos of the first string of this length
       int pos=RWfirstWithLength[l];
       do
         {
          // Search a string of this length that starts with the same character
          if (RWfirstLetters[pos]==*s)
            {
             int equals=1;
             // Compare the string
             char *aux=RWmainTable[pos]+1;
             s++;
RWProxSSearch1:
             if (--l==0) // Eureka!
                return pos+1; // +1 because the position 0 exist
RWProxSSearch2:
             if (*aux==*s)
               {
                // Next char
                equals++;
                s++;
                aux++;
                goto RWProxSSearch1;
               }
             // Is usefull the next string?
             if (RWequalCharsInNext[pos]>=equals)
               {
                // Yes!, use it, but don't waste the work allready done
                aux=RWmainTable[++pos]+equals;
                goto RWProxSSearch2;
               }
             return 0;
            }
          pos++;
         }
       while (--cant);
      }
   }
 return 0;
}

#define is_user_word(a,b) SETSE_UW_Search(a,b)
static int SETSE_UW_Search(char *s, int l)
{
 // Is in the length range?
 if (l<=UWmaxLen)
   {
    int cant=UWlenTable[l];
    // Exist any of this length?
    if (cant)
      {
       // Take the pos of the first string of this length
       int pos=UWfirstWithLength[l];
       do
         {
          // Search a string of this length that starts with the same character
          if (UWfirstLetters[pos]==*s)
            {
             int equals=1;
             // Compare the string
             char *aux=UWmainTable[pos]+1;
             s++;
UWProxSSearch1:
             if (--l==0) // Eureka!
                return pos+1;
UWProxSSearch2:
             if (*aux==*s)
               {
                // Next char
                equals++;
                s++;
                aux++;
                goto UWProxSSearch1;
               }
             // Is usefull the next string?
             if (UWequalCharsInNext[pos]>=equals)
               {
                // Yes!, use it, but don't waste the work allready done
                aux=UWmainTable[++pos]+equals;
                goto UWProxSSearch2;
               }
             return 0;
            }
          pos++;
         }
       while (--cant);
      }
   }
 return 0;
}

#define is_pascal_rword(a,b) SETSE_PR_Search(a,b)
static int SETSE_PR_Search(char *s, int l)
{
 // Is in the length range?
 if (l<=PRmaxLen)
   {
    int cant=PRlenTable[l];
    // Exist any of this length?
    if (cant)
      {
       // Take the pos of the first string of this length
       int pos=PRfirstWithLength[l];
       uchar c=tolower(*s);
       do
         {
          // Search a string of this length that starts with the same character
          if (PRfirstLetters[pos]==c)
            {
             int equals=1;
             // Compare the string
             char *aux=PRmainTable[pos]+1;
             s++; c=tolower(*s);
PRProxSSearch1:
             if (--l==0) // Eureka!
                return pos+1;
PRProxSSearch2:
             if (*aux==c)
               {
                // Next char
                equals++;
                s++; c=tolower(*s);
                aux++;
                goto PRProxSSearch1;
               }
             // Is usefull the next string?
             if (PRequalCharsInNext[pos]>=equals)
               {
                // Yes!, use it, but don't waste the work allready done
                aux=PRmainTable[++pos]+equals;
                goto PRProxSSearch2;
               }
             return 0;
            }
          pos++;
         }
       while (--cant);
      }
   }
 return 0;
}

#define is_clipper_rword(a,b) SETSE_CR_Search(a,b)
static int SETSE_CR_Search(char *s, int l)
{
 // Is in the length range?
 if (l<=CRmaxLen)
   {
    int cant=CRlenTable[l];
    // Exist any of this length?
    if (cant)
      {
       // Take the pos of the first string of this length
       int pos=CRfirstWithLength[l];
       uchar c=tolower(*s);
       do
         {
          // Search a string of this length that starts with the same character
          if (CRfirstLetters[pos]==c)
            {
             int equals=1;
             // Compare the string
             char *aux=CRmainTable[pos]+1;
             s++; c=tolower(*s);
CRProxSSearch1:
             if (--l==0) // Eureka!
                return pos+1;
CRProxSSearch2:
             if (*aux==c)
               {
                // Next char
                equals++;
                s++; c=tolower(*s);
                aux++;
                goto CRProxSSearch1;
               }
             // Is usefull the next string?
             if (CRequalCharsInNext[pos]>=equals)
               {
                // Yes!, use it, but don't waste the work allready done
                aux=CRmainTable[++pos]+equals;
                goto CRProxSSearch2;
               }
             return 0;
            }
          pos++;
         }
       while (--cant);
      }
   }
 return 0;
}

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

  Function: Boolean CreateSHShortCutTables(void)

  Initialize the search tables for ReservedWords and UserWords.

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

Boolean CreateSHShortCutTables(void)
{
 if (ReservedWords)
   {
    if (RWfirstLetters)
      {
       delete RWfirstLetters;
       RWfirstLetters=NULL;
      }
    if (!SETSECreateTables(RWfirstLetters,RWlenTable,RWfirstWithLength,
                           RWmainTable,RWequalCharsInNext,RWmaxLen,
                           ReservedWords))
       return False;
   }
 else
   RWmaxLen=0;

 if (UserWords)
   {
    if (UWfirstLetters)
      {
       delete UWfirstLetters;
       UWfirstLetters=NULL;
      }
    if (!SETSECreateTables(UWfirstLetters,UWlenTable,UWfirstWithLength,
                           UWmainTable,UWequalCharsInNext,UWmaxLen,
                           UserWords))
       return False;
   }
 else
   UWmaxLen=0;

 if (PascalRWords)
   {
    if (PRfirstLetters)
      {
       delete PRfirstLetters;
       PRfirstLetters=NULL;
      }
    if (!SETSECreateTables(PRfirstLetters,PRlenTable,PRfirstWithLength,
                           PRmainTable,PRequalCharsInNext,PRmaxLen,
                           PascalRWords))
       return False;
   }
 else
   PRmaxLen=0;

 if (ClipperRWords)
   {
    if (CRfirstLetters)
      {
       delete CRfirstLetters;
       CRfirstLetters=NULL;
      }
    if (!SETSECreateTables(CRfirstLetters,CRlenTable,CRfirstWithLength,
                           CRmainTable,CRequalCharsInNext,CRmaxLen,
                           ClipperRWords))
       return False;
   }
 else
   CRmaxLen=0;

 return True;
}


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

  Function: int is_integer_float(const char *name,uint32 l,uint32 rest)

  Parameters:
  name: string to analyze.
  l: length.
  rest: available chars in the line.

  Return:
  0 an invalid number.
  1 an integer.
  2 a float.

  Notes:
  Adapted for length.
  Added u and l.
  Added floats
  Added support for [uU][lL]{0,2} | [lL][uU]?[lL]?  |  [lL][lL]?[uU]?

  by SET based in the Robert's version.

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

#define OneOrZeroOf(a,b)                   \
         if (dispo==0) return 1;           \
         name++;                           \
         if (!isalnum(*name)) return 1;    \
         if (*name!=a && *name!=b)         \
            return 0;                      \
         dispo--

#define OkIfSepRet()                       \
         if (dispo==0) return 1;           \
         name++;                           \
         if (!isalnum(*name)) return 1

static int is_integer_float(const char *name, uint32 &dispo)
{
 while (dispo--)
  {
   if (!isdigit(*name))
     {
      if (*name=='U' || *name=='u') // [uU][lL]{0,2} with brut force
        {
         OneOrZeroOf('l','L');
         OneOrZeroOf('l','L');
         OkIfSepRet();
         return 0;
        }
      if (*name=='L'  || *name=='l') // [lL]...
        {
         OkIfSepRet();
         if (*name=='u' || *name=='U') // ...[uU][lL]?
           {
            dispo--;
            OneOrZeroOf('l','L');
            OkIfSepRet();
           }
         else
           if (*name=='l' || *name=='L') // ...[lL][uU]?
             {
              dispo--;
              OneOrZeroOf('u','U');
              OkIfSepRet();
             }
         return 0;
        }
      if (*name=='E' || *name=='e')
         goto TryFloat1;
      if (*name=='.')
         goto TryFloat0;
      if (!isalpha(*name))
        {
         dispo++;
         return 1;
        }
      return 0;
     }
   name++;
  }

 if (!dispo || *name!='.')
    return 1;

TryFloat0:
 name++;
 //dispo--;
 while (dispo--)
   {
    if (!isdigit(*name))
      {
       if (*name=='E' || *name=='e')
          goto TryFloat1;
       if (isalpha(*name) || *name=='.')
          return 0;
       else
         {
          dispo++;
          return 2;
         }
      }
    name++;
   }

 return 2;

TryFloat1:
 if (!dispo) return 0;
 name++;
 //dispo--;
 if (!isdigit(*name) && !((*name=='+' || *name=='-') && dispo && isdigit(*(name+1)))) return 0;
 name++;
 dispo--;
 while (dispo--)
   {
    if (!isdigit(*name))
      {
       if (isalpha(*name)) return 0;
       dispo++;
       return 2;
      }
    name++;
   }
 return 2;
}

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

  Function: int is_pascal_integer_float(const char *name,uint32 l,uint32 rest)

  Parameters:
  name: string to analyze.
  l: length.
  rest: available chars in the line.

  Return:
  0 an invalid number.
  1 an integer.
  2 a float.

  Notes:
  0.. is an integer + symbols.

  by SET.

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

static int is_pascal_integer_float(const char *name, uint32 &dispo)
{
 while (dispo--)
  {
   if (!isdigit(*name))
     {
      if (*name=='E' || *name=='e')
         goto TryFloat1;
      if (*name=='.')
         goto TryFloat0;
      if (!isalpha(*name))
        {
         dispo++;
         return 1;
        }
      return 0;
     }
   name++;
  }

 if (!dispo || *name!='.')
    return 1;

TryFloat0:
 name++;
 //dispo--;
 while (dispo--)
   {
    if (!isdigit(*name))
      {
       if (*name=='E' || *name=='e')
          goto TryFloat1;
       if (isalpha(*name))
          return 0;
       if (*name=='.')
         {
          dispo+=2;
          return 1;
         }
       dispo++;
       return 2;
      }
    name++;
   }

 return 2;

TryFloat1:
 if (!dispo) return 0;
 name++;
 //dispo--;
 if (!isdigit(*name) && !((*name=='+' || *name=='-') && dispo && isdigit(*(name+1)))) return 0;
 name++;
 dispo--;
 while (dispo--)
   {
    if (!isdigit(*name))
      {
       if (isalpha(*name)) return 0;
       return 2;
      }
    name++;
   }
 return 2;
}


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

  Function: int is_hex(const char *name,uint32 l)

  Parameters:
  name: string to analyze.
  l: length.

  Return:
  1 if is a valid hexadecimal number.

  Notes:
  Adapted for length.
  Added u,U,l and L.
  Added a check to avoid more than 16 digits, is that correct?

  by SET based in the Robert's version.

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

#define OneOrZeroOfHex(a,b)                \
         if (l==0) return (lori<=19);      \
         name++;                           \
         if (!isalnum(*name)) return (lori<=19);    \
         if (*name!=a && *name!=b)         \
            return 0;                      \
         l--; lori--

#define OkIfSepRetHex()                    \
         if (l==0) return (lori<=19);      \
         name++;                           \
         if (!isalnum(*name)) return (lori<=19)

static int is_hex(const char *name, uint32 l)
{
 uint32 lori=l;
 int notYetANumber=1;

 if (l<3 || (*(uint16 *)name!=0x7830 && *(uint16 *)name!=0x5830)) return 0;
 name+=2;
 l-=2;
 while (l--)
   {
    if (!isxdigit(*name))
      {
       if (*name=='U' || *name=='u') // [uU][lL]{0,2} with brut force
         {
          OneOrZeroOfHex('l','L');
          OneOrZeroOfHex('l','L');
          OkIfSepRetHex();
          return 0;
         }
       if (*name=='L'  || *name=='l') // [lL]...
         {
          OkIfSepRetHex();
          if (*name=='u' || *name=='U') // ...[uU][lL]?
            {
             l--; lori--;
             OneOrZeroOfHex('l','L');
             OkIfSepRetHex();
            }
          else
            if (*name=='l' || *name=='L') // ...[lL][uU]?
              {
               l--; lori--;
               OneOrZeroOfHex('u','U');
               OkIfSepRetHex();
              }
         }
       return 0;
      }
    if (notYetANumber)
      {
       if (*name=='0')
          lori--;
       else
          notYetANumber=0;
      }
    name++;
   }
 return (lori<=10);
}

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

  Function: int is_pascal_hex(const char *name,uint32 &dispo)

  Parameters:
  name: string to analyze.
  dispo: disponible length.

  Return:
  1 if is a valid hexadecimal number for pascal.

  by SET.

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

static int is_pascal_hex(const char *name, uint32 &dispo)
{
 name++;
 if (!isxdigit(*name))
    return 0;
 while (--dispo)
   {
    if (!isxdigit(*name))
      {
       if (*name=='.')
          return 0;
       return 1;
      }
    name++;
   }
 return 1;
}

static int is_octal(const char *name,uint32 l)
{
 // The first is a 0
 //while (*(name++)=='0') l--;
 //if (l==0) return 1;
 while (l--)
  {
   if (*name<'0' || *name>'7') return 0;
   name++;
  }
 return 1;
}


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

  Function: int is_symbol(char *name, uint32 l)

  Parameters:
  name: string to analyze.
  l: length.

  Return:
  1 if is a group of symbols.

  by SET based in a Molnar's idea.

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

static char SymbolTable[256] =
{
 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-31
 0,2,0,0,0,2,2,0,1,1,2,2,1,2,1,2,0,0,0,0,0,0,0,0,0,0,2,1,2,2,2,2, // 32-63
 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,1,2,0, // 64-95
 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,2,1,0,0, // 96-127
 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,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,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,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
};

static int is_symbol(char *name, uint32 l)
{
 int ret=0;

 while (l--)
  {
   if (!(ret=SymbolTable[(uchar)*(name++)]))
      return 0;
  }
 return ret;
}

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

  Function: int is_pascal_symbol(char *name, uint32 l)

  Parameters:
  name: string to analyze.
  l: length.

  Return:
  1 if is a group of symbols.

  Differences with C:
  @ and # are symbols.

  by SET.

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

static char SymbolTablePascal[256] =
{
 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-31
 0,2,0,2,0,2,2,0,1,1,2,2,1,2,1,2,0,0,0,0,0,0,0,0,0,0,2,1,2,2,2,2, // 32-63
 2,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,1,2,0, // 64-95
 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,2,1,0,0, // 96-127
 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,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,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,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
};

static int is_pascal_symbol(char *name, uint32 l)
{
 int ret=0;

 while (l--)
  {
   if (!(ret=SymbolTablePascal[(uchar)*(name++)]))
      return 0;
  }
 return ret;
}

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

  Function: int is_clipper_symbol(char *name, uint32 l)

  Parameters:
  name: string to analyze.
  l: length.

  Return:
  1 if is a group of symbols.

  Differences with C:
  @,# and $ are symbols.

  by SET.

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

static char SymbolTableClipper[256] =
{
 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-31
 0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1, // 32-63
 1,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,1,1,0, // 64-95
 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,1,1,0,0, // 96-127
 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,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,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,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
};

static int is_clipper_symbol(char *name, uint32 l)
{
 int ret=0;

 while (l--)
  {
   if (!(ret=SymbolTableClipper[(uchar)*(name++)]))
      return 0;
  }
 return ret;
}


inline
static int isWordChar(char c)
{
  return isalnum(c) || c == '_';
}


void SyntaxFormatLine( TCEditor * editor,
                       char *DrawBuf,
		       uint32 LinePtr,
		       int Width,
                       unsigned short Attr,
                       unsigned lineLength
		     )
{
  unsigned bufptr;
  unsigned offset;
  unsigned tabSize=editor->tabSize;
  char color;
  EDITOR = editor;
  BUFFER = editor->buffer;
  DrawBuf++;
  lineptr = LinePtr;
  bufptr = 0;
  offset = 0;

  {
    int in_c_comment=Attr & StartInCom;
    int in_string=Attr & StartString;
    uint32 word_end;
    while (offset<=lineLength && bufptr<(unsigned)Width)
     {
      char c2=0;
      int c2_valid = 0;
      word_end = offset-1;
      do
       {
        word_end++;
       }
      while (word_end <= lineLength &&
             isWordChar(BUFFER[lineptr+word_end]));

      if (word_end > lineLength ||
          (word_end > offset && !isWordChar(BUFFER[lineptr+word_end])))
        word_end--;

      {
        char *name;
        char c1;
        uint32 LenOfName;

        name=&BUFFER[lineptr+offset];
        c1=*name;
        LenOfName=word_end-offset+1;

        if (word_end+1<=lineLength)
          {
           c2_valid = 1;
           c2 = BUFFER[lineptr+offset+1];
          }

        color = NormalColor;

        if (in_c_comment)
          { // The line is commented by the last
           color = CommentColor;
           word_end=0;
           char *s=name=&BUFFER[lineptr];
           while (word_end<lineLength)
             {
              if (*s=='*')
                {
                 if (word_end<lineLength)
                   {
                    s++;
                    word_end++;
                    if (*s=='/')
                      {
                       in_c_comment=0;
                       break;
                      }
                   } // more chars
                } // '*'
              s++;
              word_end++;
             } // Of while
          } // Is c comment
        else
           if (in_string || c1 == '\"')
             {
              uint32 ll=lineLength-1;
              char *s=name + (LenOfName - 1); // if in_string LenOfName > 1
              if (!(in_string && c1 == '\"')) // the line may be start with \"
                                              // which means the end of the string
                  while (word_end<ll)
                    {
                     s++;
                     word_end++;
                     if (*s=='\\')
                       {
                        if (word_end<ll)
                          {
                           s++;
                           word_end++;
                          }
                       }
                     else
                        if (*s=='\"')
                           break;
                    }
              color = StringColor;
              in_string = 0;
             }
        else
           if (c1 == '\'')
             {
              uint32 ll=lineLength-1;
              char *s=name;
              while (word_end<ll)
                {
                 s++;
                 word_end++;
                 if (*s=='\\')
                   {
                    if (word_end<ll)
                      {
                       s++;
                       word_end++;
                      }
                   }
                 else
                    if (*s=='\'')
                       break;
                }
              color = CharColor;
             }
        else
           if (c1 == '\\')
              color = IlegalColor;
        else
           if (c1 == '#')
              color = IlegalColor;
        else
           if (c1 == '/' && c2_valid && (c2 == '/' || c2 == '*'))
             {
              color = CommentColor;
              word_end++;
              if (c2=='/')
                 word_end=lineLength-1; // Paint the rest of the line
              else
                {
                 // Search the end
                 char *s=name;
                 s++;
                 uint32 ll=lineLength-1;
                 while (word_end<ll)
                   {
                    s++;
                    word_end++;
                    if (*s=='*')
                      {
                       if (word_end<ll)
                         {
                          s++;
                          word_end++;
                          if (*s=='/')
                             break;
                         } // more chars
                      } // '*'
                   } // Of while
                } // Is c comment
             }
        else
           if ((islower(c1) || c1=='_') && is_reserved(name,LenOfName))
              color = ResColor;
        else
           if ((isalpha(c1) || c1=='_') && is_user_word(name,LenOfName))
              color = UserColor;
        else
           if (isdigit(c1))
             {
              if (c1=='0'  && c2_valid && (c2=='x' || c2=='X' || isdigit(c2)))
                {
                 // Octal or Hexa or Invalid
                 if (is_hex(name,LenOfName))
                    color=HexColor;
                 else
                    if (is_octal(name,LenOfName))
                       color=OctalColor;
                    else
                      {
                       color=IlegalColor;
                       // Is a float camuflated?
                       uint32 dispo=lineLength-word_end+LenOfName-1;
                       if (is_integer_float(name,dispo)==2)
                         {
                          color = FloatColor;
                          word_end=lineLength-dispo-1;
                         }
                      }
                }
              else
                {
                 // Integer, float or Invalid
                 // Calculate the available space in the line
                 uint32 dispo=lineLength-word_end+LenOfName-1;
                 // Check if the namber is an integer or a float or an invalid
                 // sequence
                 switch (is_integer_float(name,dispo))
                   {
                    case 0: color = IlegalColor;
                            break;
                    case 1: color = IntColor;
                            break;
                    case 2: color = FloatColor;
                            break;
                   }
                 // Adjust the length according to the routine use
                 word_end=lineLength-dispo-1;
                }
             }
        else
           if (c1=='.' && c2_valid && isdigit(c2))
             {
              uint32 dispo=lineLength-word_end+LenOfName-1;
              // Check if the namber is a float or an invalid sequence
              switch (is_integer_float(name,dispo))
                {
                 case 0: color = IlegalColor;
                         break;
                 case 2: color = FloatColor;
                         break;
                }
              // Adjust the length according to the routine use
              word_end=lineLength-dispo-1;
             }
        else
           switch (is_symbol(name,LenOfName))
             {
              case 1: color = SymbolColor;
                      break;
              case 2: color = Symbol2Color;
                      break;
             }

        while (offset<=word_end && bufptr<(unsigned)Width)
          {
           if (editor->selHided || !in_range(EDITOR->selStart,EDITOR->selEnd,lineptr+offset))
             {
              DrawBuf[bufptr*2]=color; //SetChar(color);
              if (*(name++)=='\t')
                {
                 int tabcount = tabSize-(bufptr % tabSize)-1;
                 while (tabcount--)
                   DrawBuf[(bufptr++)*2]=color; //SetChar(color);
                }
             }
           else
             {
              if (*(name++)=='\t')
                {
                 int tabcount = tabSize-(bufptr % tabSize)-1;
                 while (tabcount--) bufptr++;
                }
             }
           bufptr++;
           offset++;
          }
      }
     }
  }
}



void SyntaxFormatLineNoSel( TCEditor * editor,
                       char *DrawBuf,
		       uint32 LinePtr,
		       int Width,
                       unsigned short Attr,
                       unsigned lineLength
		     )
{
  unsigned bufptr;
  unsigned offset;
  unsigned tabSize=editor->tabSize;
  char color;
  EDITOR = editor;
  BUFFER = editor->buffer;
  DrawBuf++;
  lineptr = LinePtr;
  bufptr = 0;
  offset = 0;

  {
    int in_c_comment=Attr & StartInCom;
    int in_string=Attr & StartString;
    uint32 word_end;
    while (offset<=lineLength && bufptr<(unsigned)Width)
     {
      char c2=0;
      int c2_valid = 0;
      word_end = offset-1;
      do
       {
        word_end++;
       }
      while (word_end <= lineLength &&
             isWordChar(BUFFER[lineptr+word_end]));

      if (word_end > lineLength ||
          (word_end > offset && !isWordChar(BUFFER[lineptr+word_end])))
        word_end--;

      {
        char *name;
        char c1;
        uint32 LenOfName;

        name=&BUFFER[lineptr+offset];
        c1=*name;
        LenOfName=word_end-offset+1;

        if (word_end+1<=lineLength)
          {
           c2_valid = 1;
           c2 = BUFFER[lineptr+offset+1];
          }

        color = NormalColor;

        if (in_c_comment)
          { // The line is commented by the last
           color = CommentColor;
           word_end=0;
           char *s=name=&BUFFER[lineptr];
           while (word_end<lineLength)
             {
              if (*s=='*')
                {
                 if (word_end<lineLength)
                   {
                    s++;
                    word_end++;
                    if (*s=='/')
                      {
                       in_c_comment=0;
                       break;
                      }
                   } // more chars
                } // '*'
              s++;
              word_end++;
             } // Of while
          } // Is c comment
        else
           if (in_string || c1 == '\"')
             {
              uint32 ll=lineLength-1;
              char *s=name + (LenOfName - 1); // if in_string LenOfName > 1
              if (!(in_string && c1 == '\"')) // the line may be start with \"
                                              // which means the end of the string
                  while (word_end<ll)
                    {
                     s++;
                     word_end++;
                     if (*s=='\\')
                       {
                        if (word_end<ll)
                          {
                           s++;
                           word_end++;
                          }
                       }
                     else
                        if (*s=='\"')
                           break;
                    }
              color = StringColor;
              in_string = 0;
             }
        else
           if (c1 == '\'')
             {
              uint32 ll=lineLength-1;
              char *s=name;
              while (word_end<ll)
                {
                 s++;
                 word_end++;
                 if (*s=='\\')
                   {
                    if (word_end<ll)
                      {
                       s++;
                       word_end++;
                      }
                   }
                 else
                    if (*s=='\'')
                       break;
                }
              color = CharColor;
             }
        else
           if (c1 == '\\')
              color = IlegalColor;
        else
           if (c1 == '#')
              color = IlegalColor;
        else
           if (c1 == '/' && c2_valid && (c2 == '/' || c2 == '*'))
             {
              color = CommentColor;
              word_end++;
              if (c2=='/')
                 word_end=lineLength-1; // Paint the rest of the line
              else
                {
                 // Search the end
                 char *s=name;
                 s++;
                 uint32 ll=lineLength-1;
                 while (word_end<ll)
                   {
                    s++;
                    word_end++;
                    if (*s=='*')
                      {
                       if (word_end<ll)
                         {
                          s++;
                          word_end++;
                          if (*s=='/')
                             break;
                         } // more chars
                      } // '*'
                   } // Of while
                } // Is c comment
             }
        else
           if ((islower(c1) || c1=='_') && is_reserved(name,LenOfName))
              color = ResColor;
        else
           if ((isalpha(c1) || c1=='_') && is_user_word(name,LenOfName))
              color = UserColor;
        else
           if (isdigit(c1))
             {
              if (c1=='0'  && c2_valid && (c2=='x' || c2=='X' || isdigit(c2)))
                {
                 // Octal or Hexa or Invalid
                 if (is_hex(name,LenOfName))
                    color=HexColor;
                 else
                    if (is_octal(name,LenOfName))
                       color=OctalColor;
                    else
                      {
                       color=IlegalColor;
                       // Is a float camuflated?
                       uint32 dispo=lineLength-word_end+LenOfName-1;
                       if (is_integer_float(name,dispo)==2)
                         {
                          color = FloatColor;
                          word_end=lineLength-dispo-1;
                         }
                      }
                }
              else
                {
                 // Integer, float or Invalid
                 // Calculate the available space in the line
                 uint32 dispo=lineLength-word_end+LenOfName-1;
                 // Check if the namber is an integer or a float or an invalid
                 // sequence
                 switch (is_integer_float(name,dispo))
                   {
                    case 0: color = IlegalColor;
                            break;
                    case 1: color = IntColor;
                            break;
                    case 2: color = FloatColor;
                            break;
                   }
                 // Adjust the length according to the routine use
                 word_end=lineLength-dispo-1;
                }
             }
        else
           if (c1=='.' && c2_valid && isdigit(c2))
             {
              uint32 dispo=lineLength-word_end+LenOfName-1;
              // Check if the namber is a float or an invalid sequence
              switch (is_integer_float(name,dispo))
                {
                 case 0: color = IlegalColor;
                         break;
                 case 2: color = FloatColor;
                         break;
                }
              // Adjust the length according to the routine use
              word_end=lineLength-dispo-1;
             }
        else
           switch (is_symbol(name,LenOfName))
             {
              case 1: color = SymbolColor;
                      break;
              case 2: color = Symbol2Color;
                      break;
             }

        while (offset<=word_end && bufptr<(unsigned)Width)
          {
           DrawBuf[bufptr*2]=color;
           if (*(name++)=='\t')
             {
              int tabcount = tabSize-(bufptr % tabSize)-1;
              while (tabcount--)
                DrawBuf[(++bufptr)*2]=color;
             }
           bufptr++;
           offset++;
          }
      }
     }
  }
}


void SyntaxFormatLinePascal( TCEditor * editor,
                       char *DrawBuf,
		       uint32 LinePtr,
		       int Width,
                       int check_comment_1,
                       int check_comment_2,
                       unsigned lineLength
		     )
{
  unsigned bufptr;
  unsigned tabSize=editor->tabSize;
  unsigned offset;
  char color;
  EDITOR = editor;
  BUFFER = editor->buffer;
  DrawBuf++;
  lineptr = LinePtr;
  bufptr = 0;
  offset = 0;

  {
    int in_comment1=check_comment_1;
    int in_comment2=check_comment_2;
    uint32 word_end;
    while (offset<=lineLength && bufptr<(unsigned)Width)
     {
      char c2=0;
      int c2_valid = 0;
      word_end = offset-1;
      do
       {
        word_end++;
       }
      while (word_end <= lineLength &&
             isWordChar(BUFFER[lineptr+word_end]));

      if (word_end > lineLength ||
          (word_end > offset && !isWordChar(BUFFER[lineptr+word_end])))
        word_end--;

      {
        char *name;
        char c1;
        uint32 LenOfName;

        name=&BUFFER[lineptr+offset];
        c1=*name;
        LenOfName=word_end-offset+1;

        if (word_end+1<=lineLength)
          {
           c2_valid = 1;
           c2 = BUFFER[lineptr+offset+1];
          }

        color = NormalColor;

        if (in_comment1)
          { // The line is commented by the last
           color = CommentColor;
           word_end=0;
           char *s=name=&BUFFER[lineptr];
           while (word_end<lineLength)
             {
              s++;
              word_end++;
              if (*s=='*')
                {
                 if (word_end<lineLength)
                   {
                    s++;
                    word_end++;
                    if (*s==')')
                      {
                       in_comment1=0;
                       break;
                      }
                   } // more chars
                } // '*'
             } // Of while
          } // Is comment 1
        else
        if (in_comment2)
          { // The line is commented by the last
           color = CommentColor;
           word_end=0;
           char *s=name=&BUFFER[lineptr];
           while (word_end<lineLength)
             {
              s++;
              word_end++;
              if (*s=='}')
                {
                 in_comment2=0;
                 break;
                } // '}'
             } // Of while
          } // Is comment 2
        else
           if (c1 == '\'')
             {
              uint32 ll=lineLength-1;
              char *s=name;
              while (word_end<ll)
                {
                 s++;
                 word_end++;
                 if (*s=='\'')
                    break;
                }
              color = StringColor;
             }
        else
           if (c1 == '\\')
              color = IlegalColor;
        else
           if (c1 == '(' && c2_valid && c2 == '*')
             {
              color = CommentColor;
              word_end++;
              // Search the end
              char *s=name;
              s++;
              uint32 ll=lineLength-1;
              while (word_end<ll)
                {
                 s++;
                 word_end++;
                 if (*s=='*')
                   {
                    if (word_end<ll)
                      {
                       s++;
                       word_end++;
                       if (*s==')')
                          break;
                      } // more chars
                   } // '*'
                } // Of while
             }
        else
           if (c1 == '{')
             {
              color = CommentColor;
              word_end++;
              // Search the end
              char *s=name;
              s++;
              uint32 ll=lineLength-1;
              while (word_end<ll)
                {
                 s++;
                 word_end++;
                 if (*s=='}')
                    break;
                } // Of while
             }
        else
           if (is_pascal_rword(name,LenOfName))
              color = ResColor;
        // I think we can use the user words also for pascal
        else
           if (is_user_word(name,LenOfName))
              color = UserColor;
        else
           if (c1=='$')
             {
              uint32 dispo=lineLength-word_end+LenOfName-1;
              if (dispo && is_pascal_hex(name,dispo))
                 color=HexColor;
              else
                {
                 color=IlegalColor;
                 dispo--;
                }
              word_end=lineLength-dispo-1;
             }
        else
           if (isdigit(c1))
             {
              // Integer, float or Invalid
              // Calculate the available space in the line
              uint32 dispo=lineLength-word_end+LenOfName-1;
              // Check if the namber is an integer or a float or an invalid
              // sequence
              switch (is_pascal_integer_float(name,dispo))
                {
                 case 0: color = IlegalColor;
                         break;
                 case 1: color = IntColor;
                         break;
                 case 2: color = FloatColor;
                         break;
                }
              // Adjust the length according to the routine use
              word_end=lineLength-dispo-1;
             }
        else
           if (c1=='.' && c2_valid && isdigit(c2))
             {
              color = IlegalColor;
              word_end++;
             }
        else
           if (c1=='.' && c2_valid && c2=='.')
             {
              color = Symbol2Color;
              word_end++;
             }
        else
           switch (is_pascal_symbol(name,LenOfName))
             {
              case 1: color = SymbolColor;
                      break;
              case 2: color = Symbol2Color;
                      break;
             }

        while (offset<=word_end && bufptr<(unsigned)Width)
          {
           if (editor->selHided || !in_range(EDITOR->selStart,EDITOR->selEnd,lineptr+offset))
             {
              DrawBuf[bufptr*2]=color; //SetChar(color);
              if (*(name++)=='\t')
                {
                 int tabcount = tabSize-(bufptr % tabSize)-1;
                 while (tabcount--)
                   DrawBuf[(bufptr++)*2]=color; //SetChar(color);
                }
             }
           else
             {
              if (*(name++)=='\t')
                {
                 int tabcount = tabSize-(bufptr % tabSize)-1;
                 while (tabcount--) bufptr++;
                }
             }
           bufptr++;
           offset++;
          }
      }
     }
  }
}


void SyntaxFormatLinePascalNoSel( TCEditor * editor,
                       char *DrawBuf,
		       uint32 LinePtr,
		       int Width,
                       int check_comment_1,
                       int check_comment_2,
                       unsigned lineLength
		     )
{
  unsigned bufptr;
  unsigned tabSize=editor->tabSize;
  unsigned offset;
  char color;
  EDITOR = editor;
  BUFFER = editor->buffer;
  DrawBuf++;
  lineptr = LinePtr;
  bufptr = 0;
  offset = 0;

  {
    int in_comment1=check_comment_1;
    int in_comment2=check_comment_2;
    uint32 word_end;
    while (offset<=lineLength && bufptr<(unsigned)Width)
     {
      char c2=0;
      int c2_valid = 0;
      word_end = offset-1;
      do
       {
        word_end++;
       }
      while (word_end <= lineLength &&
             isWordChar(BUFFER[lineptr+word_end]));

      if (word_end > lineLength ||
          (word_end > offset && !isWordChar(BUFFER[lineptr+word_end])))
        word_end--;

      {
        char *name;
        char c1;
        uint32 LenOfName;

        name=&BUFFER[lineptr+offset];
        c1=*name;
        LenOfName=word_end-offset+1;

        if (word_end+1<=lineLength)
          {
           c2_valid = 1;
           c2 = BUFFER[lineptr+offset+1];
          }

        color = NormalColor;

        if (in_comment1)
          { // The line is commented by the last
           color = CommentColor;
           word_end=0;
           char *s=name=&BUFFER[lineptr];
           while (word_end<lineLength)
             {
              s++;
              word_end++;
              if (*s=='*')
                {
                 if (word_end<lineLength)
                   {
                    s++;
                    word_end++;
                    if (*s==')')
                      {
                       in_comment1=0;
                       break;
                      }
                   } // more chars
                } // '*'
             } // Of while
          } // Is comment 1
        else
        if (in_comment2)
          { // The line is commented by the last
           color = CommentColor;
           word_end=0;
           char *s=name=&BUFFER[lineptr];
           while (word_end<lineLength)
             {
              s++;
              word_end++;
              if (*s=='}')
                {
                 in_comment2=0;
                 break;
                } // '}'
             } // Of while
          } // Is comment 2
        else
           if (c1 == '\'')
             {
              uint32 ll=lineLength-1;
              char *s=name;
              while (word_end<ll)
                {
                 s++;
                 word_end++;
                 if (*s=='\'')
                    break;
                }
              color = StringColor;
             }
        else
           if (c1 == '\\')
              color = IlegalColor;
        else
           if (c1 == '(' && c2_valid && c2 == '*')
             {
              color = CommentColor;
              word_end++;
              // Search the end
              char *s=name;
              s++;
              uint32 ll=lineLength-1;
              while (word_end<ll)
                {
                 s++;
                 word_end++;
                 if (*s=='*')
                   {
                    if (word_end<ll)
                      {
                       s++;
                       word_end++;
                       if (*s==')')
                          break;
                      } // more chars
                   } // '*'
                } // Of while
             }
        else
           if (c1 == '{')
             {
              color = CommentColor;
              word_end++;
              // Search the end
              char *s=name;
              s++;
              uint32 ll=lineLength-1;
              while (word_end<ll)
                {
                 s++;
                 word_end++;
                 if (*s=='}')
                    break;
                } // Of while
             }
        else
           if (is_pascal_rword(name,LenOfName))
              color = ResColor;
        // I think we can use the user words also for pascal
        else
           if (is_user_word(name,LenOfName))
              color = UserColor;
        else
           if (c1=='$')
             {
              uint32 dispo=lineLength-word_end+LenOfName-1;
              if (dispo && is_pascal_hex(name,dispo))
                 color=HexColor;
              else
                {
                 color=IlegalColor;
                 dispo--;
                }
              word_end=lineLength-dispo-1;
             }
        else
           if (isdigit(c1))
             {
              // Integer, float or Invalid
              // Calculate the available space in the line
              uint32 dispo=lineLength-word_end+LenOfName-1;
              // Check if the namber is an integer or a float or an invalid
              // sequence
              switch (is_pascal_integer_float(name,dispo))
                {
                 case 0: color = IlegalColor;
                         break;
                 case 1: color = IntColor;
                         break;
                 case 2: color = FloatColor;
                         break;
                }
              // Adjust the length according to the routine use
              word_end=lineLength-dispo-1;
             }
        else
           if (c1=='.' && c2_valid && isdigit(c2))
             {
              color = IlegalColor;
              word_end++;
             }
        else
           if (c1=='.' && c2_valid && c2=='.')
             {
              color = Symbol2Color;
              word_end++;
             }
        else
           switch (is_pascal_symbol(name,LenOfName))
             {
              case 1: color = SymbolColor;
                      break;
              case 2: color = Symbol2Color;
                      break;
             }

        while (offset<=word_end && bufptr<(unsigned)Width)
          {
           DrawBuf[bufptr*2]=color;
           if (*(name++)=='\t')
             {
              int tabcount = tabSize-(bufptr % tabSize)-1;
              while (tabcount--)
                DrawBuf[(++bufptr)*2]=color;
             }
           bufptr++;
           offset++;
          }
      }
     }
  }
}


void SyntaxFormatLineClipper( TCEditor * editor,
                       char *DrawBuf,
		       uint32 LinePtr,
		       int Width,
                       int check_c_comment,
                       unsigned lineLength
		     )
{
  unsigned bufptr;
  unsigned offset;
  unsigned tabSize=editor->tabSize;
  char color;
  EDITOR = editor;
  BUFFER = editor->buffer;
  DrawBuf++;
  lineptr = LinePtr;
  bufptr = 0;
  offset = 0;

  {
    int in_c_comment=check_c_comment;
    uint32 word_end;
    while (offset<=lineLength && bufptr<(unsigned)Width)
     {
      char c2=0,c3=0;
      int c2_valid=0, c3_valid=0;
      word_end = offset-1;
      do
       {
        word_end++;
       }
      while (word_end <= lineLength &&
             isWordChar(BUFFER[lineptr+word_end]));

      if (word_end > lineLength ||
          (word_end > offset && !isWordChar(BUFFER[lineptr+word_end])))
        word_end--;

      {
        char *name;
        char c1;
        uint32 LenOfName;

        name=&BUFFER[lineptr+offset];
        c1=*name;
        LenOfName=word_end-offset+1;

        if (word_end+1<=lineLength)
          {
           c2_valid = 1;
           c2 = BUFFER[lineptr+offset+1];
          }
          
        if (word_end+2<=lineLength)
          {
           c3_valid = 1;
           c3 = BUFFER[lineptr+offset+2];
          }

        color = NormalColor;

        if (in_c_comment)
          { // The line is commented by the last
           color = CommentColor;
           word_end=0;
           char *s=name=&BUFFER[lineptr];
           while (word_end<lineLength)
             {
              if (*s=='*')
                {
                 if (word_end<lineLength)
                   {
                    s++;
                    word_end++;
                    if (*s=='/')
                      {
                       in_c_comment=0;
                       // Check for extra chars after the end of a comment,
                       // Clipper 5 doesn't support this
                       while (word_end<lineLength-1)
                         {
                          s++;
                          if (!isspace(*s) && *s!=26) // Let the EOF
                            {
                             word_end=lineLength-1;
                             color=IlegalColor;
                             break;
                            }
                          word_end++;
                         }
                       break;
                      }
                   } // more chars
                } // '*'
              s++;
              word_end++;
             } // Of while
          } // Is c comment
        else
           // Strings as "xxxx"
           if (c1 == '\"')
             {
              uint32 ll=lineLength-1;
              char *s=name;
              while (word_end<ll)
                {
                 s++;
                 word_end++;
                 if (*s=='\"')
                    break;
                }
              color = StringColor;
             }
        else
           // Strings as 'xxxx' are supported too
           if (c1 == '\'')
             {
              uint32 ll=lineLength-1;
              char *s=name;
              while (word_end<ll)
                {
                 s++;
                 word_end++;
                 if (*s=='\'')
                    break;
                }
              color = StringColor;
             }
        else
           if (c1 == '\\')
              color = IlegalColor;
        else
           // The C++ comments and C comments are supported
           if (c1 == '/' && c2_valid && (c2 == '/' || c2 == '*'))
             {
              color = CommentColor;
              word_end++;
              if (c2=='/')
                 word_end=lineLength-1; // Paint the rest of the line
              else
                {
                 // Search the end
                 char *s=name;
                 s++;
                 uint32 ll=lineLength-1;
                 while (word_end<ll)
                   {
                    s++;
                    word_end++;
                    if (*s=='*')
                      {
                       if (word_end<ll)
                         {
                          s++;
                          word_end++;
                          if (*s=='/')
                             break;
                         } // more chars
                      } // '*'
                   } // Of while
                } // Is c comment
             }
        else
           // The && is like // in C++, is arkaic but ...
           if (c1=='&' && c2_valid && c2=='&')
             {
              color = CommentColor;
              word_end=lineLength-1; // Paint the rest of the line
             }
        else
           // The '* -' is like // in C++, is arkaic but ...
           if (c1=='*' && c2_valid && c2==' ' && c3_valid && c3=='-')
             {
              uint32 dispo=lineLength-word_end+LenOfName-1;
              if (dispo>3)
                {
                 // Clipper 5 doesn't support this if there is no comment
                 color = CommentColor;
                 word_end=lineLength-1; // Paint the rest of the line
                }
              else
                {
                 word_end+=2;
                 color=IlegalColor;
                }
             }
        else
           if (is_clipper_rword(name,LenOfName))
              color = ResColor;
        else
           if (isdigit(c1))
             {
              // Integer, float or Invalid
              // Calculate the available space in the line
              uint32 dispo=lineLength-word_end+LenOfName-1;
              // Check if the namber is an integer or a float or an invalid
              // sequence
              switch (is_integer_float(name,dispo))
                {
                 case 0: color = IlegalColor;
                         break;
                 case 1: color = IntColor;
                         break;
                 case 2: color = FloatColor;
                         break;
                }
              // Adjust the length according to the routine use
              word_end=lineLength-dispo-1;
             }
        else
           // Clipper supports .NNNN floats
           if (c1=='.' && c2_valid && isdigit(c2))
             {
              uint32 dispo=lineLength-word_end+LenOfName-1;
              // Check if the number is a float or an invalid sequence
              switch (is_integer_float(name,dispo))
                {
                 case 0: color = IlegalColor;
                         break;
                 case 2: color = FloatColor;
                         break;
                }
              // Adjust the length according to the routine use
              word_end=lineLength-dispo-1;
             }
        else
           // .t. .f. .and. .or. are special
           if (c1=='.' && c2_valid && isalpha(c2))
             {
              uint32 ll=lineLength-1;
              int ok=0;
              char *s=name+1;
              char *s1=s;
              while (word_end<ll)
                {
                 s++;
                 word_end++;
                 if (*s=='.')
                   {
                    word_end++;
                    ll=(uint32)(s-s1);
                    switch (ll)
                      {
                       case 1:
                            ok = *s1=='t' || *s1=='T' || *s1=='f' ||
                                 *s1=='F' || *s1=='y' || *s1=='Y' ||
                                 *s1=='n' || *s1=='N';
                            break;
                       case 2:
                            ok = (*s1=='o' || *s1=='O') &&
                                 (*(s1+1)=='r' || *(s1+1)=='R');
                            break;
                       case 3:
                            ok = ((*s1=='a'     || *s1=='A') &&
                                  (*(s1+1)=='n' || *(s1+1)=='N') &&
                                  (*(s1+2)=='d' || *(s1+2)=='D')) ||
                                 ((*s1=='n'     || *s1=='N') &&
                                  (*(s1+1)=='o' || *(s1+1)=='O') &&
                                  (*(s1+2)=='t' || *(s1+2)=='T'));
                            break;
                      }
                    if (ok)
                       color = ResColor;
                    else
                       color = IlegalColor;
                    break;
                   }
                 if (!isalpha(*s))
                   {
                    color = IlegalColor;
                    break;
                   }
                }
             }
        else
           if (is_clipper_symbol(name,LenOfName))
              color = SymbolColor;

        while (offset<=word_end && bufptr<(unsigned)Width)
          {
           if (editor->selHided || !in_range(EDITOR->selStart,EDITOR->selEnd,lineptr+offset))
             {
              DrawBuf[bufptr*2]=color; //SetChar(color);
              if (*(name++)=='\t')
                {
                 int tabcount = tabSize-(bufptr % tabSize)-1;
                 while (tabcount--)
                   DrawBuf[(bufptr++)*2]=color; //SetChar(color);
                }
             }
           else
             {
              if (*(name++)=='\t')
                {
                 int tabcount = tabSize-(bufptr % tabSize)-1;
                 while (tabcount--) bufptr++;
                }
             }
           bufptr++;
           offset++;
          }
      }
     }
  }
}

void SyntaxFormatLineClipperNoSel( TCEditor * editor,
                       char *DrawBuf,
		       uint32 LinePtr,
		       int Width,
                       int check_c_comment,
                       unsigned lineLength
		     )
{
  unsigned bufptr;
  unsigned offset;
  unsigned tabSize=editor->tabSize;
  char color;
  EDITOR = editor;
  BUFFER = editor->buffer;
  DrawBuf++;
  lineptr = LinePtr;
  bufptr = 0;
  offset = 0;

  {
    int in_c_comment=check_c_comment;
    uint32 word_end;
    while (offset<=lineLength && bufptr<(unsigned)Width)
     {
      char c2=0,c3=0;
      int c2_valid=0, c3_valid=0;
      word_end = offset-1;
      do
       {
        word_end++;
       }
      while (word_end <= lineLength &&
             isWordChar(BUFFER[lineptr+word_end]));

      if (word_end > lineLength ||
          (word_end > offset && !isWordChar(BUFFER[lineptr+word_end])))
        word_end--;

      {
        char *name;
        char c1;
        uint32 LenOfName;

        name=&BUFFER[lineptr+offset];
        c1=*name;
        LenOfName=word_end-offset+1;

        if (word_end+1<=lineLength)
          {
           c2_valid = 1;
           c2 = BUFFER[lineptr+offset+1];
          }
          
        if (word_end+2<=lineLength)
          {
           c3_valid = 1;
           c3 = BUFFER[lineptr+offset+2];
          }

        color = NormalColor;

        if (in_c_comment)
          { // The line is commented by the last
           color = CommentColor;
           word_end=0;
           char *s=name=&BUFFER[lineptr];
           while (word_end<lineLength)
             {
              if (*s=='*')
                {
                 if (word_end<lineLength)
                   {
                    s++;
                    word_end++;
                    if (*s=='/')
                      {
                       in_c_comment=0;
                       // Check for extra chars after the end of a comment,
                       // Clipper 5 doesn't support this
                       while (word_end<lineLength-1)
                         {
                          s++;
                          if (!isspace(*s) && *s!=26) // Let the EOF
                            {
                             word_end=lineLength-1;
                             color=IlegalColor;
                             break;
                            }
                          word_end++;
                         }
                       break;
                      }
                   } // more chars
                } // '*'
              s++;
              word_end++;
             } // Of while
          } // Is c comment
        else
           // Strings as "xxxx"
           if (c1 == '\"')
             {
              uint32 ll=lineLength-1;
              char *s=name;
              while (word_end<ll)
                {
                 s++;
                 word_end++;
                 if (*s=='\"')
                    break;
                }
              color = StringColor;
             }
        else
           // Strings as 'xxxx' are supported too
           if (c1 == '\'')
             {
              uint32 ll=lineLength-1;
              char *s=name;
              while (word_end<ll)
                {
                 s++;
                 word_end++;
                 if (*s=='\'')
                    break;
                }
              color = StringColor;
             }
        else
           if (c1 == '\\')
              color = IlegalColor;
        else
           // The C++ comments and C comments are supported
           if (c1 == '/' && c2_valid && (c2 == '/' || c2 == '*'))
             {
              color = CommentColor;
              word_end++;
              if (c2=='/')
                 word_end=lineLength-1; // Paint the rest of the line
              else
                {
                 // Search the end
                 char *s=name;
                 s++;
                 uint32 ll=lineLength-1;
                 while (word_end<ll)
                   {
                    s++;
                    word_end++;
                    if (*s=='*')
                      {
                       if (word_end<ll)
                         {
                          s++;
                          word_end++;
                          if (*s=='/')
                             break;
                         } // more chars
                      } // '*'
                   } // Of while
                } // Is c comment
             }
        else
           // The && is like // in C++, is arkaic but ...
           if (c1=='&' && c2_valid && c2=='&')
             {
              color = CommentColor;
              word_end=lineLength-1; // Paint the rest of the line
             }
        else
           // The '* -' is like // in C++, is arkaic but ...
           if (c1=='*' && c2_valid && c2==' ' && c3_valid && c3=='-')
             {
              uint32 dispo=lineLength-word_end+LenOfName-1;
              if (dispo>3)
                {
                 // Clipper 5 doesn't support this if there is no comment
                 color = CommentColor;
                 word_end=lineLength-1; // Paint the rest of the line
                }
              else
                {
                 word_end+=2;
                 color=IlegalColor;
                }
             }
        else
           if (is_clipper_rword(name,LenOfName))
              color = ResColor;
        else
           if (isdigit(c1))
             {
              // Integer, float or Invalid
              // Calculate the available space in the line
              uint32 dispo=lineLength-word_end+LenOfName-1;
              // Check if the namber is an integer or a float or an invalid
              // sequence
              switch (is_integer_float(name,dispo))
                {
                 case 0: color = IlegalColor;
                         break;
                 case 1: color = IntColor;
                         break;
                 case 2: color = FloatColor;
                         break;
                }
              // Adjust the length according to the routine use
              word_end=lineLength-dispo-1;
             }
        else
           // Clipper supports .NNNN floats
           if (c1=='.' && c2_valid && isdigit(c2))
             {
              uint32 dispo=lineLength-word_end+LenOfName-1;
              // Check if the number is a float or an invalid sequence
              switch (is_integer_float(name,dispo))
                {
                 case 0: color = IlegalColor;
                         break;
                 case 2: color = FloatColor;
                         break;
                }
              // Adjust the length according to the routine use
              word_end=lineLength-dispo-1;
             }
        else
           // .t. .f. .and. .or. are special
           if (c1=='.' && c2_valid && isalpha(c2))
             {
              uint32 ll=lineLength-1;
              int ok=0;
              char *s=name+1;
              char *s1=s;
              while (word_end<ll)
                {
                 s++;
                 word_end++;
                 if (*s=='.')
                   {
                    word_end++;
                    ll=(uint32)(s-s1);
                    switch (ll)
                      {
                       case 1:
                            ok = *s1=='t' || *s1=='T' || *s1=='f' ||
                                 *s1=='F' || *s1=='y' || *s1=='Y' ||
                                 *s1=='n' || *s1=='N';
                            break;
                       case 2:
                            ok = (*s1=='o' || *s1=='O') &&
                                 (*(s1+1)=='r' || *(s1+1)=='R');
                            break;
                       case 3:
                            ok = ((*s1=='a'     || *s1=='A') &&
                                  (*(s1+1)=='n' || *(s1+1)=='N') &&
                                  (*(s1+2)=='d' || *(s1+2)=='D')) ||
                                 ((*s1=='n'     || *s1=='N') &&
                                  (*(s1+1)=='o' || *(s1+1)=='O') &&
                                  (*(s1+2)=='t' || *(s1+2)=='T'));
                            break;
                      }
                    if (ok)
                       color = ResColor;
                    else
                       color = IlegalColor;
                    break;
                   }
                 if (!isalpha(*s))
                   {
                    color = IlegalColor;
                    break;
                   }
                }
             }
        else
           if (is_clipper_symbol(name,LenOfName))
              color = SymbolColor;

        while (offset<=word_end && bufptr<(unsigned)Width)
          {
           DrawBuf[bufptr*2]=color;
           if (*(name++)=='\t')
             {
              int tabcount = tabSize-(bufptr % tabSize)-1;
              while (tabcount--)
                DrawBuf[(++bufptr)*2]=color;
             }
           bufptr++;
           offset++;
          }
      }
     }
  }
}
