///////////////////////////////////////////////////////////////////////////// // Name: No names yet. // Purpose: Contrib. demo // Author: Aleksandras Gluchovas // Modified by: // Created: 22/09/98 // RCS-ID: $Id$ // Copyright: (c) Aleskandars Gluchovas // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include "wx/wx.h" #endif #if defined( wxUSE_TEMPLATE_STL ) # include #else # include "wxstlac.h" #endif #include "sourcepainter.h" const int MAX_KEYWORD_LEN = 16; struct KeywordT { char keyWord[MAX_KEYWORD_LEN]; int rank; }; // source fragment ranks : // 0 - nomral text // 1 - basic types // 2 - reserved words // multil-language keywords map static KeywordT __gKeyWords[] = { { "for", 1 }, { "FOR", 1 }, { "For", 1 }, { "next", 1 }, { "Next", 1 }, { "NEXT", 1 }, { "if", 1 }, { "If", 1 }, { "IF", 1 }, { "then", 1 }, { "Then", 1 }, { "THEN", 1 }, { "else", 1 }, { "Else", 1 }, { "ELSE", 1 }, { "do", 1 }, { "Do", 1 }, { "DO", 1 }, { "break", 1 }, { "Break", 1 }, { "BREAK", 1 }, { "continue", 1 }, { "goto", 1 }, { "Goto", 1 }, { "GOTO", 1 }, { "switch", 1 }, { "default", 1 }, { "case", 1 }, { "repeat", 1 }, { "Repeat", 1 }, { "REPEAT", 1 }, { "until", 1 }, { "Until", 1 }, { "UNTIL", 1 }, { "return", 1 }, { "Return", 1 }, { "RETURN", 1 }, { "unit", 1 }, { "Unit", 1 }, { "UNIT", 1 }, { "procedure", 1 }, { "Procedure", 1 }, { "PROCEDURE", 1 }, { "function", 1 }, { "Function", 1 }, { "FUNCTION", 1 }, { "begin", 1 }, { "Begin", 1 }, { "BEGIN", 1 }, { "End", 1 }, { "END", 1 }, //////////////////////////////////////////////////// { "enum", 1 }, { "static", 1 }, { "const", 1 }, { "mutable", 1 }, { "volatile", 1 }, { "__asm", 1 }, { "asm", 1 }, { "typeid", 1 }, { "sizeof", 1 }, { "typeof", 1 }, { "native", 1 }, { "#include", 1 }, { "#define", 1 }, { "#def", 1 }, { "#undef", 1 }, { "#ifdef", 1 }, { "#ifndef", 1 }, { "#if", 1 }, { "#endif", 1 }, { "#elif", 1 }, { "#else", 1 }, { "#pragma", 1 }, { "#line", 1 }, { "package", 1 }, { "import", 1 }, { "export", 1 }, //////////////////////////////////////////////////// { "dynamic_cast", 1 }, { "const_cast", 1 }, //////// some hacks for VB ///////// { "sub", 1 }, { "Sub", 1 }, { "SUB", 1 }, { "as", 1 }, { "As", 1 }, { "AS", 1 }, /////// data types /////// { "int" , 1 }, { "integer", 1 }, { "Integer", 1 }, { "INTEGER", 1 }, { "real", 1 }, { "Real", 1 }, { "REAL", 1 }, { "float", 1 }, { "Float", 1 }, { "FLOAT", 1 }, { "char", 1 }, { "Char", 1 }, { "CHAR", 1 }, { "register", 1 }, { "string", 1 }, { "String", 1 }, { "STRING", 1 }, { "array", 1 }, { "Array", 1 }, { "ARRAY", 1 }, { "packed", 1 }, { "Packed", 1 }, { "PACKED", 1 }, { "property", 1 }, { "Property", 1 }, { "PROPERTY", 1 }, { "unsigned", 1 }, { "long", 1 }, { "double", 1 }, { "short", 1 }, { "bool", 1 }, { "longint", 1 }, { "Longint", 1 }, { "LONGINT", 1 }, { "extended", 1 }, { "Extended", 1 }, { "EXTENTED", 1 }, { "pointer", 1 }, { "Pointer", 1 }, { "POINTER", 1 }, { "and", 1 }, { "And", 1 }, { "AND", 1 }, { "or", 1 }, { "Or", 1 }, { "OR", 1 }, { "xor", 1 }, { "Xor", 1 }, { "XOR", 1 }, { "void", 1 }, { "__stdcall", 1 }, { "__declspec", 1 }, { "extern", 1 }, { "stdcall", 1 }, { "dllimport", 1 }, { "dllexport", 1 }, { "__cdecl", 1 }, { "cdecl", 1 }, { "template", 1 }, { "typedef", 1 }, { "naked", 1 }, { "try", 1 }, { "catch", 1 }, { "throw", 2 }, // C++ { "throws", 1 }, // Java { "finalize", 1 }, // "STL-suport" { "size_t", 1 }, { "NPOS", 1 }, { "vector", 1 }, { "list", 1 }, { "map", 1 }, { "multimap", 1 }, { "external", 1 }, { "External", 1 }, { "EXTERNAL", 1 }, //////////// meta-information ////////////// { "virtual", 2 }, { "Virtual", 2 }, { "override", 2 }, { "Override", 2 }, { "class", 2 }, { "Class", 2 }, { "CLASS", 2 }, { "struct", 2 }, { "union", 2 }, { "record", 2 }, { "Record", 2 }, { "RECORD", 2 }, { "form", 1 }, { "Form", 1 }, { "FORM", 1 }, { "namespace", 2 }, { "interface" , 2 }, { "abstract", 2 }, { "Interface" , 2 }, { "INTERFACE" , 2 }, { "implementation", 2 }, { "Implementation", 2 }, { "IMPLEMENTATION", 2 }, { "label", 2 }, { "Label", 2 }, { "LABEL", 2 }, { "implements", 2 }, { "public", 2 }, { "private", 2 }, { "protected", 2 }, { "this", 2 }, { "This", 2 }, { "THIS", 2 }, { "new", 2 }, { "New", 2 }, { "NEW", 2 }, { "delete", 2 }, { "inline", 2 }, { "operator", 2 }, { "Inherited", 2 }, { "Inherited", 2 }, { "final", 2 }, { "implements", 2 }, { "super", 2 }, // even more... { "java", 2 }, { "Java", 2 }, { "JAVA", 2 }, { "delphi", 2 }, { "Delphi", 2 }, { "SmallTalk", 2 }, { "Smalltalk", 2 }, { "smalltalk", 2 }, { "assembler", 2 }, { "Assembler", 2 }, { "Basic", 2 }, { "BASIC", 2 }, { "basic", 2 }, { "CORBA", 2 }, { "COBOL", 2 }, { "ADA", 2 }, { "LISP", 2 }, // just for fun... { "life", 2 }, { "sucks", 2 }, { "rules", 2 }, { "Quake", 2 }, { "QuakeWorld", 2 }, { "[ag_slammer]",2 }, { "Aleksandras", 2 }, { "Gluchovas" , 2 }, { "Alex", 2 }, { "alex", 2 }, { "aleks", 2 }, { "aleksas", 3 }, { "AlexSoft", 2 }, { "Alexsoft", 2 }, { "SpringSky", 2 }, { "SK_Team", 2 }, { "soften", 2 }, { "UB40", 2 }, { "U96", 2 } }; struct less_c_str { inline bool operator()( char* x, char* y) const { return ( strcmp( x,y ) < 0 ); } }; #if defined( wxUSE_TEMPLATE_STL ) typedef map< char*, char*, less_c_str > KeywordMapT; #else typedef char* CharPtrT; typedef WXSTL_MAP( CharPtrT, CharPtrT ,less_c_str) KeywordMapT; #endif static KeywordMapT __gMultiLangMap; static int __gMapReady = 0; void check_keyword_map( int keywordMapNr ) { if ( !__gMapReady ) { __gMapReady = 1; // "make sure" the address of the first member of non-polimorphic class // coinsides with the address of the instance /* KeywordT dummy; if ( (char*)& dummy != &dummy.keyWord[0] ) throw; */ int size = sizeof(__gKeyWords) / sizeof( KeywordT ); for( int i = 0; i != size; ++i ) __gMultiLangMap.insert( KeywordMapT::value_type( (char*)&__gKeyWords[i], (char*)&__gKeyWords[i] ) ); } } int get_rank( char* start, char* end ) { // FIXME:: what if end is no longer leagal adress? char tmp = *end; *end = '\0'; // put temporary terminator KeywordMapT::iterator i; if ( (i = __gMultiLangMap.find( start ) ) != __gMultiLangMap.end() ) { KeywordT* pKey = (KeywordT*)(*i).second; *end = tmp; return pKey->rank; } else { *end = tmp; return 0; } } static inline void store_range( SPBlockListT& results, int rank, int range_len ) { if ( !range_len ) return; results.push_back ( ( rank << 16 ) | ( range_len ) ); } #define STORE_RANGE store_range( results, cur_rank, cur_range_len );\ cur_rank = cur_range_len = 0; #define NEXT_CHAR cur_range_len++; \ ++cur; \ continue; static inline int is_alpha( char ch ) { return ( (( ch >= '_' ) && ( ch <= 'z' )) || (( ch >= 'A' ) && ( ch <= 'Z' )) ); } // _ . . // Ziema atEjo netikEtai static void heighlight_syntax( char* str, int strLen, SPBlockListT& results, bool& isComment ) { bool isMultiline = 0; char* cur = str; char* end = str + strLen; int cur_rank = ( isComment == 1 ) ? RANK_GREEN : RANK_BLACK; int cur_range_len = 0; while ( cur != end ) { int has_next = ( cur+1 != end ); if ( isComment ) { if ( *cur == '*' ) if ( has_next && *(cur+1) == '/' ) { // turn off multiline comment mode cur += 2; cur_range_len += 2; isComment = 0; isMultiline = 0; STORE_RANGE; continue; } ++cur_range_len; ++cur; continue; } /* if ( *cur == 10 ) if ( isComment ) if ( isMultiline ) { cur_rank = RANK_GREEN; cur_range_len = end - cur; STORE_RANGE; isComment = 0; isMultiline = 0; continue; }*/ if ( *cur == '/' ) { if ( has_next ) { if ( *(cur+1) == '/' ) { STORE_RANGE; char* eol = cur; while ( eol < end && *eol != 10 ) ++eol; cur_rank = RANK_GREEN; cur_range_len = eol - cur; cur = eol; STORE_RANGE; continue; } if ( *(cur+1) == '*' ) { STORE_RANGE; cur_rank = RANK_GREEN; cur_range_len = 2; isComment = 1; cur += 2; isMultiline = 1; continue; } } NEXT_CHAR; } if ( ( is_alpha( *cur ) || *(cur) == '#' ) && has_next ) { if ( is_alpha( *(cur+1) ) ) { char* start = cur; cur += 2; while ( cur != end && is_alpha(*cur) ) ++cur; int wordRank; if ( (wordRank = get_rank( start, cur )) > 0 ) { STORE_RANGE; store_range( results, wordRank, int(cur-start) ); cur_rank = cur_range_len = 0; continue; } cur_range_len += ( cur-start ); continue; } else NEXT_CHAR; } NEXT_CHAR; } if ( cur_range_len > 0 ) STORE_RANGE; } /***** Implementation for class SourcePainter ******/ SourcePainter::SourcePainter( bool assembleResultString ) : mCollectResultsOn( assembleResultString ), mIsInComment( FALSE ), mCommentIsMultiline( FALSE ) { check_keyword_map(0); } void SourcePainter::ProcessSource( char* src, int srcLen ) { // TBD:: multilne state... heighlight_syntax( src, srcLen, mBlocks, mIsInComment ); if ( mCollectResultsOn ) mResultStr += string( src, srcLen ); } void SourcePainter::SetState( bool isInComment, bool commentIsMultiline ) { mIsInComment = isInComment; mCommentIsMultiline = commentIsMultiline; } void SourcePainter::Init(bool assembleResultString) { mIsInComment = 0; mCommentIsMultiline = 0; mCollectResultsOn = assembleResultString; mResultStr = ""; mBlocks.erase( mBlocks.begin(), mBlocks.end() ); } static int rank_tags_map[] = { TAG_BLACK_FONT, TAG_BLUE_FONT, TAG_RED_FONT, TAG_GREEN_FONT }; void SourcePainter::GetResultString(string& result, MarkupTagsT tags) { // this method works, only if results of processing // are collected // ASSERT( mCollectResultsOn ); result = ""; int pos = 0; for( size_t i = 0; i != mBlocks.size(); ++i ) { int desc = mBlocks[i]; int len = desc & 0xFFFF; int rank = (desc >> 16) & 0xFFFF; result += tags[ rank_tags_map[rank] ].start; for( int n = 0; n != len; ++n ) result += mResultStr[pos+n]; pos += len; result += tags[ rank_tags_map[rank] ].end; } } SPBlockListT& SourcePainter::GetBlocks() { return mBlocks; } bool SourcePainter::IsKeyword( char* word, int wordLen ) { check_keyword_map(0); int rank = get_rank( word, word + wordLen ); return ( rank == RANK_BLUE || rank == RANK_RED ); }