///////////////////////////////////////////////////////////////////////////
//
//  Copyright:  Stcherbatchenko Andrei
//  E-mail:     windfall@gmx.de
//
//  Implementation of the CCrystalEditView class, a part of the Crystal Edit -
//  syntax coloring text editor.
//
//  You are free to use or modify this code to the following restrictions:
//  - Acknowledge me somewhere in your about box, simple "Parts of code by.."
//  will be enough. If you can't (or don't want to), contact me personally.
//  - LEAVE THIS HEADER INTACT
////////////////////////////////////////////////////////////////////////////
 
#include <coolprj/pch.h>
#pragma hdrstop
 
#include <coolprj/cooledit.h>
 
using namespace owl;
 
//  C++ keywords (MSVC5.0 + POET5.0)
static LPCTSTR s_apszCppKeywordList[] =
{
  _T("__asm"),
  _T("__based"),
  _T("__cdecl"),
  _T("__declspec"),
  _T("__except"),
  _T("__export"),
  _T("__far16"),
  _T("__fastcall"),
  _T("__finally"),
  _T("__inline"),
  _T("__int16"),
  _T("__int32"),
  _T("__int64"),
  _T("__int8"),
  _T("__leave"),
  _T("__multiple_inheritance"),
  _T("__pascal"),
  _T("__single_inheritance"),
  _T("__stdcall"),
  _T("__syscall"),
  _T("__try"),
  _T("__uuidof"),
  _T("__virtual_inheritance"),
  _T("_asm"),
  _T("_cdecl"),
  _T("_export"),
  _T("_far16"),
  _T("_fastcall"),
  _T("_pascal"),
  _T("_persistent"),
  _T("_stdcall"),
  _T("_syscall"),
  _T("auto"),
  _T("bool"),
  _T("break"),
  _T("case"),
  _T("catch"),
  _T("char"),
  _T("class"),
  _T("const"),
  _T("const_cast"),
  _T("constexpr"),
  _T("continue"),
  _T("decltype"),
  _T("default"),
  _T("delete"),
  _T("depend"),
  _T("dllexport"),
  _T("dllimport"),
  _T("do"),
  _T("double"),
  _T("dynamic_cast"),
  _T("else"),
  _T("enum"),
  _T("explicit"),
  _T("extern"),
  _T("false"),
  _T("float"),
  _T("for"),
  _T("friend"),
  _T("goto"),
  _T("if"),
  _T("inline"),
  _T("int"),
  _T("interface"),
  _T("long"),
  _T("main"),
  _T("mutable"),
  _T("naked"),
  _T("namespace"),
  _T("new"),
  _T("ondemand"),
  _T("operator"),
  _T("override"),
  _T("persistent"),
  _T("private"),
  _T("protected"),
  _T("public"),
  _T("register"),
  _T("reinterpret_cast"),
  _T("return"),
  _T("short"),
  _T("signed"),
  _T("sizeof"),
  _T("static"),
  _T("static_cast"),
  _T("struct"),
  _T("switch"),
  _T("template"),
  _T("this"),
  _T("thread"),
  _T("throw"),
  _T("true"),
  _T("try"),
  _T("typedef"),
  _T("typeid"),
  _T("typename"),
  _T("union"),
  _T("unsigned"),
  _T("using"),
  _T("uuid"),
  _T("virtual"),
  _T("void"),
  _T("volatile"),
  _T("while"),
  _T("wmain"),
  _T("xalloc"),
  NULL
};
 
 
/*
static bool
IsUser1Keyword (LPCTSTR pszChars, int nLength)
{
  return IsXKeyword (s_apszUser1KeywordList, pszChars, nLength);
}
*/
 
static bool IsCppKeyword(LPCTSTR pszChars, int len)
{
  for (int i = 0; s_apszCppKeywordList[i] != NULL; i ++){
    if(_tcsncmp(s_apszCppKeywordList[i], pszChars, len) == 0
        && s_apszCppKeywordList[i][len] == 0)
      return true;
  }
  return false;
}
 
static bool
IsCppNumber(LPCTSTR pszChars, int len)
{
  if (len > 2 && pszChars[0] == _T('0') && pszChars[1] == _T('x')){
    for (int I = 2; I < len; I++){
      if (_istdigit(pszChars[I]) || (pszChars[I] >= _T('A') &&
           pszChars[I] <= _T('F')) || (pszChars[I] >= _T('a') &&
           pszChars[I] <= _T('f')))
        continue;
      return false;
    }
    return true;
  }
  if (!_istdigit(pszChars[0]))
    return false;
  for (int I = 1; I < len; I++){
    if (! _istdigit(pszChars[I]) && pszChars[I] != _T('+') &&
      pszChars[I] != _T('-') && pszChars[I] != _T('.') && pszChars[I] != _T('e') &&
      pszChars[I] != _T('E'))
      return false;
  }
  return true;
}
 
inline void DefineBlock(TCoolTextWnd::TTextBlock* pBuf, int& actualItems, int pos, int syntaxindex)
{
  CHECK(pos >= 0);
  if(pBuf){
    if (actualItems == 0 || pBuf[actualItems - 1].CharPos <= pos){
      pBuf[actualItems].CharPos     = pos;
      pBuf[actualItems].SyntaxIndex = syntaxindex;
      actualItems++;
    }
  }
}
#if 0
#define DEFINE_BLOCK(pos, syntaxindex)  \
  CHECK((pos) >= 0 && (pos) <= len);\
  if (pBuf != NULL){\
    if (actualItems == 0 || pBuf[actualItems - 1].CharPos <= (pos)){\
      pBuf[actualItems].CharPos     = (pos);\
      pBuf[actualItems].SyntaxIndex = (syntaxindex);\
      actualItems++;\
    }\
  }
#else
#define DEFINE_BLOCK(pos, syntaxindex)\
  DefineBlock(pBuf, actualItems, pos, syntaxindex)
#endif
 
#define COOKIE_COMMENT        0x0001
#define COOKIE_PREPROCESSOR    0x0002
#define COOKIE_EXT_COMMENT    0x0004
#define COOKIE_STRING          0x0008
#define COOKIE_CHAR            0x0010
#define COOKIE_OPERATOR        0x0020
 
//
//
//
//
struct TCSyntaxParser: public TSyntaxParser {
  public:
    TCSyntaxParser(TCoolTextWnd* parent):TSyntaxParser(parent){}
    uint32 ParseLine(uint32 cookie, int index, TCoolTextWnd::TTextBlock* buf, int& items);
};
//
_COOLEDFUNC(TSyntaxParser*) CParserCreator(TCoolTextWnd* parent)
{
  return  new TCSyntaxParser(parent);
}
//
uint32 TCSyntaxParser::ParseLine(uint32 cookie, int index,
                                 TCoolTextWnd::TTextBlock* pBuf,
                                 int& actualItems)
{
  int len = Parent->GetLineLength(index);
  if (len <= 0)
    return cookie & COOKIE_EXT_COMMENT;
 
  LPCTSTR pszChars = GetLineText(index);
  bool bFirstChar     = (cookie & ~COOKIE_EXT_COMMENT) == 0;
  bool bRedefineBlock = true;
  bool bDecIndex      = false;
  bool bWasCommentStart = false;
  int nIdentBegin      = -1;
  int I;
  for(I = 0; ; I++){
    if (bRedefineBlock){
      int nPos = I;
      if (bDecIndex){
        nPos--;
        //actualItems--;
      }
      bRedefineBlock = false;
      bDecIndex      = false;
      if (cookie & (COOKIE_COMMENT | COOKIE_EXT_COMMENT)){
        DEFINE_BLOCK(nPos, COLORINDEX_COMMENT);
      }
      else if (cookie & COOKIE_STRING){
        DEFINE_BLOCK(nPos, COLORINDEX_STRING);
      }
      else if (cookie & COOKIE_CHAR){
        DEFINE_BLOCK(nPos, COLORINDEX_CHARACTER);
      }
      else if (cookie & COOKIE_PREPROCESSOR){
        DEFINE_BLOCK(nPos, COLORINDEX_PREPROCESSOR);
      }
      else{
        //DEFINE_BLOCK(nPos, COLORINDEX_NORMALTEXT);
        if (xisalnum(pszChars[nPos]) ||
          (
            nPos > 0 &&
            pszChars[nPos] == _T('.') &&
            !xisalpha(pszChars[nPos - 1]) &&
            !xisalpha(pszChars[nPos + 1])
          ))
        {
          DEFINE_BLOCK (nPos, COLORINDEX_NORMALTEXT);
        }
        else{
          DEFINE_BLOCK (nPos, COLORINDEX_OPERATOR);
          bRedefineBlock = true;
          bDecIndex = true;
        }
      }
    }
 
    if (I == len)
      break;
 
    if (cookie & COOKIE_COMMENT){
      DEFINE_BLOCK(I, COLORINDEX_COMMENT);
      cookie |= COOKIE_COMMENT;
      break;
    }
 
    //  String constant "...."
    if (cookie & COOKIE_STRING)
    {
      if (pszChars[I] == '"' &&
        (
          I == 0 || // "...
          (I >= 1 && pszChars[I - 1] != '\\') || // ...?"...
          (I >= 2 && pszChars[I - 1] == '\\' && pszChars[I - 2] == '\\') // ...\\"...
          // TODO: What about ...\\\"...?
        ))
      {
        cookie &= ~COOKIE_STRING;
        bRedefineBlock = true;
      }
      continue;
    }
 
    //  Char constant '..'
    if (cookie & COOKIE_CHAR)
    {
      if (pszChars[I] == '\'' &&
        (
          I == 0 || // '...
          (I >= 1 && pszChars[I - 1] != '\\') || // ...?'...
          (I >= 2 && pszChars[I - 1] == '\\' && pszChars[I - 2] == '\\') // ...\\'...
          // TODO: What about ...\\\'...?
        ))
      {
        cookie &= ~COOKIE_CHAR;
        bRedefineBlock = true;
      }
      continue;
    }
 
    //  Extended comment /*....*/
    if (cookie & COOKIE_EXT_COMMENT){
      //if (I > 0 && pszChars[I] == _T('/') && pszChars[I - 1] == _T('*')){
      if ((I > 1 && pszChars[I] == _T('/') && pszChars[I - 1] == _T('*') &&
           !bWasCommentStart) ||
           (I == 1 && pszChars[I] == _T('/') && pszChars[I - 1] == _T('*'))){
 
        cookie &= ~COOKIE_EXT_COMMENT;
        bRedefineBlock = true;
      }
      continue;
    }
 
    if (I > 0 && pszChars[I] == _T('/') && pszChars[I - 1] == _T('/')){
      DEFINE_BLOCK(I - 1, COLORINDEX_COMMENT);
      cookie |= COOKIE_COMMENT;
      break;
    }
 
    //  Preprocessor directive #....
    if (cookie & COOKIE_PREPROCESSOR){
      if (I > 0 && pszChars[I] == _T('*') && pszChars[I - 1] == _T('/')){
        DEFINE_BLOCK(I - 1, COLORINDEX_COMMENT);
        //bRedefineBlock = true; // let work in redefine block
        cookie |= COOKIE_EXT_COMMENT;
      }
      continue;
    }
 
    //  Normal text
    if(pszChars[I] == _T('"')){
      DEFINE_BLOCK(I, COLORINDEX_STRING);
      //bRedefineBlock = true; // let work in redefine block
      cookie |= COOKIE_STRING;
      continue;
    }
    if (pszChars[I] == _T('\'')){
      DEFINE_BLOCK(I, COLORINDEX_CHARACTER);
      //bRedefineBlock = true; // let work in redefine block
      cookie |= COOKIE_CHAR;
      continue;
    }
    if (I > 0 && pszChars[I] == _T('*') && pszChars[I - 1] == _T('/')){
      DEFINE_BLOCK(I - 1, COLORINDEX_COMMENT);
      //bRedefineBlock = true; // let work in redefine block
      cookie |= COOKIE_EXT_COMMENT;
      continue;
    }
 
    bWasCommentStart = false;
 
    if (bFirstChar){
      if (pszChars[I] == _T('#')){
        DEFINE_BLOCK(I, COLORINDEX_PREPROCESSOR);
        cookie |= COOKIE_PREPROCESSOR;
        continue;
      }
      if (!_istspace(pszChars[I]))
        bFirstChar = FALSE;
    }
 
    if (pBuf == NULL)
      continue;  //  We don't need to extract keywords,
 
    //  for faster parsing skip the rest of loop
    if (xisalnum (pszChars[I]) ||
      (
        I > 0 &&
        pszChars[I] == _T('.') &&
        !xisalpha (pszChars[I - 1]) &&
        !xisalpha (pszChars[I + 1])
      ))
    {
      if (nIdentBegin == -1)
        nIdentBegin = I;
    }
    else{
      if (nIdentBegin >= 0){
        if (IsCppKeyword(pszChars + nIdentBegin, I - nIdentBegin)){
          DEFINE_BLOCK(nIdentBegin, COLORINDEX_KEYWORD);
        }
//        else if (IsUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin)){
//          DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
//        }
        else if (IsCppNumber(pszChars + nIdentBegin, I - nIdentBegin)){
          DEFINE_BLOCK(nIdentBegin, COLORINDEX_NUMBER);
        }
        else{
          bool bFunction = false;
          for (int j = I; j < len; j++){
            if(!_istspace(pszChars[j])){
              if(pszChars[j] == _T('('))
                bFunction = true;
              break;
            }
          }
          if(bFunction){
            DEFINE_BLOCK(nIdentBegin, COLORINDEX_FUNCNAME);
          }
        }
        bRedefineBlock = true;
        bDecIndex = true;
        nIdentBegin = -1;
      }
    }
  }
 
  if (nIdentBegin >= 0){
    if (IsCppKeyword(pszChars + nIdentBegin, I - nIdentBegin)){
      DEFINE_BLOCK(nIdentBegin, COLORINDEX_KEYWORD);
    }
//    else if (IsUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin)){
//      DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
//    }
    else if (IsCppNumber(pszChars + nIdentBegin, I - nIdentBegin)){
      DEFINE_BLOCK(nIdentBegin, COLORINDEX_NUMBER);
    }
    else{
      bool bFunction = false;
      for(int j = I; j < len; j++){
        if(!_istspace(pszChars[j])){
          if(pszChars[j] == _T('('))
            bFunction = true;
          break;
        }
      }
      if (bFunction){
        DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
      }
    }
  }
  if (pszChars[len - 1] != _T('\\'))
    cookie &= COOKIE_EXT_COMMENT;
  return cookie;
}
//

V781 The value of the 'nPos' index is checked after it was used. Perhaps there is a mistake in program logic.

V781 The value of the 'I' index is checked after it was used. Perhaps there is a mistake in program logic.

V560 A part of conditional expression is always true: I >= 1.

V560 A part of conditional expression is always true: I >= 1.