/** * Scintilla source code edit control * @file LexMySQL.cxx * Lexer for MySQL * * Improved by Mike Lischke * Adopted from LexSQL.cxx by Anders Karlsson * Original work by Neil Hodgson * Copyright 1998-2005 by Neil Hodgson * The License.txt file describes the conditions under which this software may be distributed. */ #include #include #include #include #include #include "Platform.h" #include "PropSet.h" #include "Accessor.h" #include "StyleContext.h" #include "KeyWords.h" #include "Scintilla.h" #include "SciLexer.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_'); } static inline bool IsAWordStart(int ch) { return (ch < 0x80) && (isalpha(ch) || ch == '_'); } static inline bool IsADoxygenChar(int ch) { return (islower(ch) || ch == '$' || ch == '@' || ch == '\\' || ch == '&' || ch == '<' || ch == '>' || ch == '#' || ch == '{' || ch == '}' || ch == '[' || ch == ']'); } static inline bool IsANumberChar(int ch) { // Not exactly following number definition (several dots are seen as OK, etc.) // but probably enough in most cases. return (ch < 0x80) && (isdigit(ch) || toupper(ch) == 'E' || ch == '.' || ch == '-' || ch == '+'); } //-------------------------------------------------------------------------------------------------- /** * Check if the current content context represent a keyword and set the context state if so. */ static void CheckForKeyword(StyleContext& sc, WordList* keywordlists[]) { int length = sc.LengthCurrent() + 1; // +1 for the next char char* s = new char[length]; sc.GetCurrentLowered(s, length); if (keywordlists[0]->InList(s)) sc.ChangeState(SCE_MYSQL_MAJORKEYWORD); else if (keywordlists[1]->InList(s)) sc.ChangeState(SCE_MYSQL_KEYWORD); else if (keywordlists[2]->InList(s)) sc.ChangeState(SCE_MYSQL_DATABASEOBJECT); else if (keywordlists[3]->InList(s)) sc.ChangeState(SCE_MYSQL_FUNCTION); else if (keywordlists[5]->InList(s)) sc.ChangeState(SCE_MYSQL_PROCEDUREKEYWORD); else if (keywordlists[6]->InList(s)) sc.ChangeState(SCE_MYSQL_USER1); else if (keywordlists[7]->InList(s)) sc.ChangeState(SCE_MYSQL_USER2); else if (keywordlists[8]->InList(s)) sc.ChangeState(SCE_MYSQL_USER3); delete [] s; } //-------------------------------------------------------------------------------------------------- static void ColouriseMySQLDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { // Determine if the current state should terminate. switch (sc.state) { case SCE_MYSQL_OPERATOR: sc.SetState(SCE_MYSQL_DEFAULT); break; case SCE_MYSQL_NUMBER: // We stop the number definition on non-numerical non-dot non-eE non-sign char. if (!IsANumberChar(sc.ch)) sc.SetState(SCE_MYSQL_DEFAULT); break; case SCE_MYSQL_IDENTIFIER: // Switch from identifier to keyword state and open a new state for the new char. if (!IsAWordChar(sc.ch)) { CheckForKeyword(sc, keywordlists); // Additional check for function keywords needed. // A function name must be followed by an opening parenthesis. if (sc.state == SCE_MYSQL_FUNCTION && sc.ch != '(') sc.ChangeState(SCE_MYSQL_DEFAULT); sc.SetState(SCE_MYSQL_DEFAULT); } break; case SCE_MYSQL_VARIABLE: if (!IsAWordChar(sc.ch)) sc.SetState(SCE_MYSQL_DEFAULT); break; case SCE_MYSQL_SYSTEMVARIABLE: if (!IsAWordChar(sc.ch)) { int length = sc.LengthCurrent() + 1; char* s = new char[length]; sc.GetCurrentLowered(s, length); // Check for known system variables here. if (keywordlists[4]->InList(&s[2])) sc.ChangeState(SCE_MYSQL_KNOWNSYSTEMVARIABLE); delete [] s; sc.SetState(SCE_MYSQL_DEFAULT); } break; case SCE_MYSQL_QUOTEDIDENTIFIER: if (sc.ch == '`') { if (sc.chNext == '`') sc.Forward(); // Ignore it else sc.ForwardSetState(SCE_MYSQL_DEFAULT); } break; case SCE_MYSQL_COMMENT: case SCE_MYSQL_HIDDENCOMMAND: if (sc.Match('*', '/')) { sc.Forward(); sc.ForwardSetState(SCE_MYSQL_DEFAULT); } break; case SCE_MYSQL_COMMENTLINE: if (sc.atLineStart) sc.SetState(SCE_MYSQL_DEFAULT); break; case SCE_MYSQL_SQSTRING: if (sc.ch == '\\') sc.Forward(); // Escape sequence else if (sc.ch == '\'') { // End of single quoted string reached? if (sc.chNext == '\'') sc.Forward(); else sc.ForwardSetState(SCE_MYSQL_DEFAULT); } break; case SCE_MYSQL_DQSTRING: if (sc.ch == '\\') sc.Forward(); // Escape sequence else if (sc.ch == '\"') { // End of single quoted string reached? if (sc.chNext == '\"') sc.Forward(); else sc.ForwardSetState(SCE_MYSQL_DEFAULT); } break; } // Determine if a new state should be entered. if (sc.state == SCE_MYSQL_DEFAULT) { switch (sc.ch) { case '@': if (sc.chNext == '@') { sc.SetState(SCE_MYSQL_SYSTEMVARIABLE); sc.Forward(2); // Skip past @@. } else if (IsAWordStart(sc.ch)) { sc.SetState(SCE_MYSQL_VARIABLE); sc.Forward(); // Skip past @. } else sc.SetState(SCE_MYSQL_OPERATOR); break; case '`': sc.SetState(SCE_MYSQL_QUOTEDIDENTIFIER); break; case '#': sc.SetState(SCE_MYSQL_COMMENTLINE); break; case '\'': sc.SetState(SCE_MYSQL_SQSTRING); break; case '\"': sc.SetState(SCE_MYSQL_DQSTRING); break; default: if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) sc.SetState(SCE_MYSQL_NUMBER); else if (IsAWordStart(sc.ch)) sc.SetState(SCE_MYSQL_IDENTIFIER); else if (sc.Match('/', '*')) { sc.SetState(SCE_MYSQL_COMMENT); // Skip comment introducer and check for hidden command. sc.Forward(2); if (sc.ch == '!') { sc.ChangeState(SCE_MYSQL_HIDDENCOMMAND); sc.Forward(); } } else if (sc.Match("--")) { // Special MySQL single line comment. sc.SetState(SCE_MYSQL_COMMENTLINE); sc.Forward(2); // Check the third character too. It must be a space or EOL. if (sc.ch != ' ' && sc.ch != '\n' && sc.ch != '\r') sc.ChangeState(SCE_MYSQL_OPERATOR); } else if (isoperator(static_cast(sc.ch))) sc.SetState(SCE_MYSQL_OPERATOR); } } } // Do a final check for keywords if we currently have an identifier, to highlight them // also at the end of a line. if (sc.state == SCE_MYSQL_IDENTIFIER) { CheckForKeyword(sc, keywordlists); // Additional check HTTP/1.1 200 OK Connection: keep-alive Connection: keep-alive Content-Disposition: inline; filename="LexMySQL.cxx" Content-Disposition: inline; filename="LexMySQL.cxx" Content-Length: 16123 Content-Length: 16123 Content-Security-Policy: default-src 'none' Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Type: text/plain; charset=UTF-8 Date: Mon, 17 Nov 2025 23:29:20 UTC ETag: "f29a183cd0141063b2ca584e07956fe66326444b" ETag: "f29a183cd0141063b2ca584e07956fe66326444b" Expires: Thu, 15 Nov 2035 23:29:20 GMT Expires: Thu, 15 Nov 2035 23:29:20 GMT Last-Modified: Mon, 17 Nov 2025 23:29:20 GMT Last-Modified: Mon, 17 Nov 2025 23:29:20 GMT Server: OpenBSD httpd Server: OpenBSD httpd X-Content-Type-Options: nosniff X-Content-Type-Options: nosniff /** * Scintilla source code edit control * @file LexMySQL.cxx * Lexer for MySQL * * Improved by Mike Lischke * Adopted from LexSQL.cxx by Anders Karlsson * Original work by Neil Hodgson * Copyright 1998-2005 by Neil Hodgson * The License.txt file describes the conditions under which this software may be distributed. */ #include #include #include #include #include #include "Platform.h" #include "PropSet.h" #include "Accessor.h" #include "StyleContext.h" #include "KeyWords.h" #include "Scintilla.h" #include "SciLexer.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif static inline bool IsAWordChar(int ch) { return (ch < 0x80) && (isalnum(ch) || ch == '_'); } static inline bool IsAWordStart(int ch) { return (ch < 0x80) && (isalpha(ch) || ch == '_'); } static inline bool IsADoxygenChar(int ch) { return (islower(ch) || ch == '$' || ch == '@' || ch == '\\' || ch == '&' || ch == '<' || ch == '>' || ch == '#' || ch == '{' || ch == '}' || ch == '[' || ch == ']'); } static inline bool IsANumberChar(int ch) { // Not exactly following number definition (several dots are seen as OK, etc.) // but probably enough in most cases. return (ch < 0x80) && (isdigit(ch) || toupper(ch) == 'E' || ch == '.' || ch == '-' || ch == '+'); } //-------------------------------------------------------------------------------------------------- /** * Check if the current content context represent a keyword and set the context state if so. */ static void CheckForKeyword(StyleContext& sc, WordList* keywordlists[]) { int length = sc.LengthCurrent() + 1; // +1 for the next char char* s = new char[length]; sc.GetCurrentLowered(s, length); if (keywordlists[0]->InList(s)) sc.ChangeState(SCE_MYSQL_MAJORKEYWORD); else if (keywordlists[1]->InList(s)) sc.ChangeState(SCE_MYSQL_KEYWORD); else if (keywordlists[2]->InList(s)) sc.ChangeState(SCE_MYSQL_DATABASEOBJECT); else if (keywordlists[3]->InList(s)) sc.ChangeState(SCE_MYSQL_FUNCTION); else if (keywordlists[5]->InList(s)) sc.ChangeState(SCE_MYSQL_PROCEDUREKEYWORD); else if (keywordlists[6]->InList(s)) sc.ChangeState(SCE_MYSQL_USER1); else if (keywordlists[7]->InList(s)) sc.ChangeState(SCE_MYSQL_USER2); else if (keywordlists[8]->InList(s)) sc.ChangeState(SCE_MYSQL_USER3); delete [] s; } //-------------------------------------------------------------------------------------------------- static void ColouriseMySQLDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) { StyleContext sc(startPos, length, initStyle, styler); for (; sc.More(); sc.Forward()) { // Determine if the current state should terminate. switch (sc.state) { case SCE_MYSQL_OPERATOR: sc.SetState(SCE_MYSQL_DEFAULT); break; case SCE_MYSQL_NUMBER: // We stop the number definition on non-numerical non-dot non-eE non-sign char. if (!IsANumberChar(sc.ch)) sc.SetState(SCE_MYSQL_DEFAULT); break; case SCE_MYSQL_IDENTIFIER: // Switch from identifier to keyword state and open a new state for the new char. if (!IsAWordChar(sc.ch)) { CheckForKeyword(sc, keywordlists); // Additional check for function keywords needed. // A function name must be followed by an opening parenthesis. if (sc.state == SCE_MYSQL_FUNCTION && sc.ch != '(') sc.ChangeState(SCE_MYSQL_DEFAULT); sc.SetState(SCE_MYSQL_DEFAULT); } break; case SCE_MYSQL_VARIABLE: if (!IsAWordChar(sc.ch)) sc.SetState(SCE_MYSQL_DEFAULT); break; case SCE_MYSQL_SYSTEMVARIABLE: if (!IsAWordChar(sc.ch)) { int length = sc.LengthCurrent() + 1; char* s = new char[length]; sc.GetCurrentLowered(s, length); // Check for known system variables here. if (keywordlists[4]->InList(&s[2])) sc.ChangeState(SCE_MYSQL_KNOWNSYSTEMVARIABLE); delete [] s; sc.SetState(SCE_MYSQL_DEFAULT); } break; case SCE_MYSQL_QUOTEDIDENTIFIER: if (sc.ch == '`') { if (sc.chNext == '`') sc.Forward(); // Ignore it else sc.ForwardSetState(SCE_MYSQL_DEFAULT); } break; case SCE_MYSQL_COMMENT: case SCE_MYSQL_HIDDENCOMMAND: if (sc.Match('*', '/')) { sc.Forward(); sc.ForwardSetState(SCE_MYSQL_DEFAULT); } break; case SCE_MYSQL_COMMENTLINE: if (sc.atLineStart) sc.SetState(SCE_MYSQL_DEFAULT); break; case SCE_MYSQL_SQSTRING: if (sc.ch == '\\') sc.Forward(); // Escape sequence else if (sc.ch == '\'') { // End of single quoted string reached? if (sc.chNext == '\'') sc.Forward(); else sc.ForwardSetState(SCE_MYSQL_DEFAULT); } break; case SCE_MYSQL_DQSTRING: if (sc.ch == '\\') sc.Forward(); // Escape sequence else if (sc.ch == '\"') { // End of single quoted string reached? if (sc.chNext == '\"') sc.Forward(); else sc.ForwardSetState(SCE_MYSQL_DEFAULT); } break; } // Determine if a new state should be entered. if (sc.state == SCE_MYSQL_DEFAULT) { switch (sc.ch) { case '@': if (sc.chNext == '@') { sc.SetState(SCE_MYSQL_SYSTEMVARIABLE); sc.Forward(2); // Skip past @@. } else if (IsAWordStart(sc.ch)) { sc.SetState(SCE_MYSQL_VARIABLE); sc.Forward(); // Skip past @. } else sc.SetState(SCE_MYSQL_OPERATOR); break; case '`': sc.SetState(SCE_MYSQL_QUOTEDIDENTIFIER); break; case '#': sc.SetState(SCE_MYSQL_COMMENTLINE); break; case '\'': sc.SetState(SCE_MYSQL_SQSTRING); break; case '\"': sc.SetState(SCE_MYSQL_DQSTRING); break; default: if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) sc.SetState(SCE_MYSQL_NUMBER); else if (IsAWordStart(sc.ch)) sc.SetState(SCE_MYSQL_IDENTIFIER); else if (sc.Match('/', '*')) { sc.SetState(SCE_MYSQL_COMMENT); // Skip comment introducer and c