]> git.saurik.com Git - wxWidgets.git/blob - utils/HelpGen/src/sourcepainter.cpp
fixes for rotated text drawing
[wxWidgets.git] / utils / HelpGen / src / sourcepainter.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: No names yet.
3 // Purpose: Contrib. demo
4 // Author: Aleksandras Gluchovas
5 // Modified by:
6 // Created: 22/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Aleskandars Gluchovas
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #ifndef WX_PRECOMP
20 #include "wx/wx.h"
21 #endif
22
23 #if defined( wxUSE_TEMPLATE_STL )
24
25 #include <map>
26 #else
27
28 #include "wxstlac.h"
29
30 #endif
31
32 #include "sourcepainter.h"
33
34 const int MAX_KEYWORD_LEN = 16;
35
36 struct KeywordT
37 {
38 char keyWord[MAX_KEYWORD_LEN];
39 int rank;
40 };
41
42 // source fragment ranks :
43
44 // 0 - nomral text
45 // 1 - basic types
46 // 2 - reserved words
47
48 // multil-language keywords map
49
50 static KeywordT __gKeyWords[] =
51 {
52 { "for", 1 },
53 { "FOR", 1 },
54 { "For", 1 },
55
56 { "next", 1 },
57 { "Next", 1 },
58 { "NEXT", 1 },
59
60 { "if", 1 },
61 { "If", 1 },
62 { "IF", 1 },
63
64 { "then", 1 },
65 { "Then", 1 },
66 { "THEN", 1 },
67
68 { "else", 1 },
69 { "Else", 1 },
70 { "ELSE", 1 },
71
72 { "do", 1 },
73 { "Do", 1 },
74 { "DO", 1 },
75
76
77 { "break", 1 },
78 { "Break", 1 },
79 { "BREAK", 1 },
80
81 { "continue", 1 },
82
83 { "goto", 1 },
84 { "Goto", 1 },
85 { "GOTO", 1 },
86
87 { "switch", 1 },
88 { "default", 1 },
89 { "case", 1 },
90
91 { "repeat", 1 },
92 { "Repeat", 1 },
93 { "REPEAT", 1 },
94
95 { "until", 1 },
96 { "Until", 1 },
97 { "UNTIL", 1 },
98
99 { "return", 1 },
100 { "Return", 1 },
101 { "RETURN", 1 },
102
103 { "unit", 1 },
104 { "Unit", 1 },
105 { "UNIT", 1 },
106
107 { "procedure", 1 },
108 { "Procedure", 1 },
109 { "PROCEDURE", 1 },
110
111 { "function", 1 },
112 { "Function", 1 },
113 { "FUNCTION", 1 },
114
115 { "begin", 1 },
116 { "Begin", 1 },
117 { "BEGIN", 1 },
118
119 { "End", 1 },
120 { "END", 1 },
121
122 ////////////////////////////////////////////////////
123
124 { "enum", 1 },
125 { "static", 1 },
126 { "const", 1 },
127 { "mutable", 1 },
128 { "volatile", 1 },
129 { "__asm", 1 },
130 { "asm", 1 },
131
132 { "typeid", 1 },
133 { "sizeof", 1 },
134 { "typeof", 1 },
135
136
137 { "native", 1 },
138
139 { "#include", 1 },
140 { "#define", 1 },
141 { "#def", 1 },
142 { "#undef", 1 },
143 { "#ifdef", 1 },
144 { "#ifndef", 1 },
145 { "#if", 1 },
146 { "#endif", 1 },
147 { "#elif", 1 },
148 { "#else", 1 },
149 { "#pragma", 1 },
150 { "#line", 1 },
151
152 { "package", 1 },
153 { "import", 1 },
154 { "export", 1 },
155
156 ////////////////////////////////////////////////////
157
158 { "dynamic_cast", 1 },
159 { "const_cast", 1 },
160
161 //////// some hacks for VB /////////
162
163 { "sub", 1 },
164 { "Sub", 1 },
165 { "SUB", 1 },
166 { "as", 1 },
167 { "As", 1 },
168 { "AS", 1 },
169
170 /////// data types ///////
171
172 { "int" , 1 },
173 { "integer", 1 },
174 { "Integer", 1 },
175 { "INTEGER", 1 },
176
177 { "real", 1 },
178 { "Real", 1 },
179 { "REAL", 1 },
180
181 { "float", 1 },
182 { "Float", 1 },
183 { "FLOAT", 1 },
184
185 { "char", 1 },
186 { "Char", 1 },
187 { "CHAR", 1 },
188
189 { "register", 1 },
190
191 { "string", 1 },
192 { "String", 1 },
193 { "STRING", 1 },
194
195 { "array", 1 },
196 { "Array", 1 },
197 { "ARRAY", 1 },
198
199 { "packed", 1 },
200 { "Packed", 1 },
201 { "PACKED", 1 },
202
203 { "property", 1 },
204 { "Property", 1 },
205 { "PROPERTY", 1 },
206
207 { "unsigned", 1 },
208
209 { "long", 1 },
210 { "double", 1 },
211 { "short", 1 },
212 { "bool", 1 },
213
214 { "longint", 1 },
215 { "Longint", 1 },
216 { "LONGINT", 1 },
217
218 { "extended", 1 },
219 { "Extended", 1 },
220 { "EXTENTED", 1 },
221
222 { "pointer", 1 },
223 { "Pointer", 1 },
224 { "POINTER", 1 },
225
226 { "and", 1 },
227 { "And", 1 },
228 { "AND", 1 },
229 { "or", 1 },
230 { "Or", 1 },
231 { "OR", 1 },
232 { "xor", 1 },
233 { "Xor", 1 },
234 { "XOR", 1 },
235
236 { "void", 1 },
237 { "__stdcall", 1 },
238 { "__declspec", 1 },
239 { "extern", 1 },
240 { "stdcall", 1 },
241 { "dllimport", 1 },
242 { "dllexport", 1 },
243 { "__cdecl", 1 },
244 { "cdecl", 1 },
245 { "template", 1 },
246 { "typedef", 1 },
247 { "naked", 1 },
248
249 { "try", 1 },
250 { "catch", 1 },
251 { "throw", 2 }, // C++
252 { "throws", 1 }, // Java
253
254
255 { "finalize", 1 },
256
257 // "STL-suport"
258
259 { "size_t", 1 },
260 { "NPOS", 1 },
261 { "vector", 1 },
262 { "list", 1 },
263 { "map", 1 },
264 { "multimap", 1 },
265
266 { "external", 1 },
267 { "External", 1 },
268 { "EXTERNAL", 1 },
269
270 //////////// meta-information //////////////
271
272 { "virtual", 2 },
273 { "Virtual", 2 },
274
275 { "override", 2 },
276 { "Override", 2 },
277
278 { "class", 2 },
279 { "Class", 2 },
280 { "CLASS", 2 },
281
282 { "struct", 2 },
283 { "union", 2 },
284
285 { "record", 2 },
286 { "Record", 2 },
287 { "RECORD", 2 },
288
289 { "form", 1 },
290 { "Form", 1 },
291 { "FORM", 1 },
292
293 { "namespace", 2 },
294
295 { "interface" , 2 },
296 { "abstract", 2 },
297
298 { "Interface" , 2 },
299 { "INTERFACE" , 2 },
300
301 { "implementation", 2 },
302 { "Implementation", 2 },
303 { "IMPLEMENTATION", 2 },
304
305 { "label", 2 },
306 { "Label", 2 },
307 { "LABEL", 2 },
308
309 { "implements", 2 },
310
311 { "public", 2 },
312 { "private", 2 },
313 { "protected", 2 },
314
315 { "this", 2 },
316 { "This", 2 },
317 { "THIS", 2 },
318
319 { "new", 2 },
320 { "New", 2 },
321 { "NEW", 2 },
322
323 { "delete", 2 },
324 { "inline", 2 },
325
326 { "operator", 2 },
327
328 { "Inherited", 2 },
329 { "Inherited", 2 },
330
331 { "final", 2 },
332 { "implements", 2 },
333 { "super", 2 },
334
335 // even more...
336 { "java", 2 },
337 { "Java", 2 },
338 { "JAVA", 2 },
339 { "delphi", 2 },
340 { "Delphi", 2 },
341 { "SmallTalk", 2 },
342 { "Smalltalk", 2 },
343 { "smalltalk", 2 },
344 { "assembler", 2 },
345 { "Assembler", 2 },
346 { "Basic", 2 },
347 { "BASIC", 2 },
348 { "basic", 2 },
349 { "CORBA", 2 },
350 { "COBOL", 2 },
351 { "ADA", 2 },
352 { "LISP", 2 },
353
354 // just for fun...
355 { "life", 2 },
356 { "sucks", 2 },
357 { "rules", 2 },
358 { "Quake", 2 },
359 { "QuakeWorld", 2 },
360 { "[ag_slammer]",2 },
361 { "Aleksandras", 2 },
362 { "Gluchovas" , 2 },
363 { "Alex", 2 },
364 { "alex", 2 },
365 { "aleks", 2 },
366 { "aleksas", 3 },
367 { "AlexSoft", 2 },
368 { "Alexsoft", 2 },
369 { "SpringSky", 2 },
370 { "SK_Team", 2 },
371 { "soften", 2 },
372 { "UB40", 2 },
373 { "U96", 2 }
374 };
375
376 struct less_c_str
377 {
378 inline bool operator()( char* x, char* y) const
379 { return ( strcmp( x,y ) < 0 );
380 }
381 };
382
383 #if defined( wxUSE_TEMPLATE_STL )
384
385 typedef map< char*, char*, less_c_str > KeywordMapT;
386
387 #else
388
389 typedef char* CharPtrT;
390 typedef WXSTL_MAP( CharPtrT, CharPtrT ,less_c_str) KeywordMapT;
391
392 #endif
393
394 static KeywordMapT __gMultiLangMap;
395 static int __gMapReady = 0;
396
397 void check_keyword_map( int keywordMapNr )
398 {
399 if ( !__gMapReady )
400 {
401 __gMapReady = 1;
402
403 // "make sure" the address of the first member of non-polimorphic class
404 // coinsides with the address of the instance
405
406 /*
407 KeywordT dummy;
408
409 if ( (char*)& dummy != &dummy.keyWord[0] )
410 throw;
411 */
412
413 int size = sizeof(__gKeyWords) / sizeof( KeywordT );
414
415 for( int i = 0; i != size; ++i )
416
417 __gMultiLangMap.insert(
418 KeywordMapT::value_type( (char*)&__gKeyWords[i],
419 (char*)&__gKeyWords[i]
420 )
421 );
422 }
423 }
424
425 int get_rank( char* start, char* end )
426 {
427 // FIXME:: what if end is no longer leagal adress?
428
429 char tmp = *end;
430 *end = '\0'; // put temporary terminator
431
432 KeywordMapT::iterator i;
433
434 if ( (i = __gMultiLangMap.find( start ) ) != __gMultiLangMap.end() )
435 {
436 KeywordT* pKey = (KeywordT*)(*i).second;
437
438 *end = tmp;
439
440 return pKey->rank;
441 }
442 else
443 {
444 *end = tmp;
445 return 0;
446 }
447 }
448
449 static inline void store_range( SPBlockListT& results, int rank, int range_len )
450 {
451 if ( !range_len ) return;
452
453 results.push_back ( ( rank << 16 ) | ( range_len ) );
454 }
455
456
457 #define STORE_RANGE store_range( results, cur_rank, cur_range_len );\
458 cur_rank = cur_range_len = 0;
459
460 #define NEXT_CHAR cur_range_len++; \
461 ++cur; \
462 continue;
463
464 static inline int is_alpha( char ch )
465 {
466 return ( (( ch >= '_' ) && ( ch <= 'z' )) ||
467 (( ch >= 'A' ) && ( ch <= 'Z' ))
468 );
469 }
470
471 // _ . .
472 // Ziema atEjo netikEtai
473
474 static void heighlight_syntax( char* str, int strLen,
475 SPBlockListT& results, bool& isComment )
476 {
477 bool isMultiline = 0;
478 char* cur = str;
479 char* end = str + strLen;
480
481 int cur_rank = ( isComment == 1 ) ? RANK_GREEN : RANK_BLACK;
482 int cur_range_len = 0;
483
484 while ( cur != end )
485 {
486 int has_next = ( cur+1 != end );
487
488 if ( isComment )
489 {
490 if ( *cur == '*' )
491 if ( has_next && *(cur+1) == '/' )
492 {
493 // turn off multiline comment mode
494 cur += 2;
495 cur_range_len += 2;
496 isComment = 0;
497 isMultiline = 0;
498 STORE_RANGE;
499
500 continue;
501 }
502
503 ++cur_range_len;
504 ++cur;
505 continue;
506 }
507
508 /*
509 if ( *cur == 10 )
510 if ( isComment )
511 if ( isMultiline )
512 {
513 cur_rank = RANK_GREEN;
514 cur_range_len = end - cur;
515 STORE_RANGE;
516 isComment = 0;
517 isMultiline = 0;
518 continue;
519 }*/
520
521 if ( *cur == '/' )
522 {
523 if ( has_next )
524 {
525 if ( *(cur+1) == '/' )
526 {
527 STORE_RANGE;
528
529 char* eol = cur;
530 while ( eol < end && *eol != 10 )
531 ++eol;
532
533 cur_rank = RANK_GREEN;
534 cur_range_len = eol - cur;
535 cur = eol;
536 STORE_RANGE;
537
538 continue;
539 }
540
541 if ( *(cur+1) == '*' )
542 {
543 STORE_RANGE;
544 cur_rank = RANK_GREEN;
545 cur_range_len = 2;
546 isComment = 1;
547 cur += 2;
548 isMultiline = 1;
549 continue;
550 }
551 }
552
553 NEXT_CHAR;
554 }
555
556 if ( ( is_alpha( *cur ) || *(cur) == '#' )
557 && has_next
558 )
559 {
560 if ( is_alpha( *(cur+1) ) )
561 {
562 char* start = cur;
563 cur += 2;
564
565 while ( cur != end && is_alpha(*cur) ) ++cur;
566
567 int wordRank;
568
569 if ( (wordRank = get_rank( start, cur )) > 0 )
570 {
571 STORE_RANGE;
572
573 store_range( results, wordRank, int(cur-start) );
574 cur_rank = cur_range_len = 0;
575 continue;
576 }
577
578 cur_range_len += ( cur-start );
579 continue;
580 }
581 else
582 NEXT_CHAR;
583 }
584
585 NEXT_CHAR;
586 }
587
588 if ( cur_range_len > 0 ) STORE_RANGE;
589 }
590
591 /***** Implementation for class SourcePainter ******/
592
593 SourcePainter::SourcePainter( bool assembleResultString )
594 : mCollectResultsOn( assembleResultString ),
595 mIsInComment( FALSE ),
596 mCommentIsMultiline( FALSE )
597 {
598 check_keyword_map(0);
599 }
600
601 void SourcePainter::ProcessSource( char* src, int srcLen )
602 {
603 // TBD:: multilne state...
604
605 heighlight_syntax( src, srcLen, mBlocks, mIsInComment );
606
607 if ( mCollectResultsOn )
608
609 mResultStr += string( src, srcLen );
610 }
611
612 void SourcePainter::SetState( bool isInComment,
613 bool commentIsMultiline )
614 {
615 mIsInComment = isInComment;
616 mCommentIsMultiline = commentIsMultiline;
617 }
618
619 void SourcePainter::Init(bool assembleResultString)
620 {
621 mIsInComment = 0;
622 mCommentIsMultiline = 0;
623 mCollectResultsOn = assembleResultString;
624
625 mResultStr = "";
626
627 mBlocks.erase( mBlocks.begin(), mBlocks.end() );
628 }
629
630 static int rank_tags_map[] =
631 {
632 TAG_BLACK_FONT,
633 TAG_BLUE_FONT,
634 TAG_RED_FONT,
635 TAG_GREEN_FONT
636 };
637
638 void SourcePainter::GetResultString(string& result, MarkupTagsT tags)
639 {
640 // this method works, only if results of processing
641 // are collected
642 // ASSERT( mCollectResultsOn );
643 result = "";
644
645 int pos = 0;
646
647 for( size_t i = 0; i != mBlocks.size(); ++i )
648 {
649 int desc = mBlocks[i];
650
651 int len = desc & 0xFFFF;
652 int rank = (desc >> 16) & 0xFFFF;
653
654 result += tags[ rank_tags_map[rank] ].start;
655
656 for( int n = 0; n != len; ++n )
657
658 result += mResultStr[pos+n];
659
660 pos += len;
661
662 result += tags[ rank_tags_map[rank] ].end;
663 }
664 }
665
666 SPBlockListT& SourcePainter::GetBlocks()
667 {
668 return mBlocks;
669 }
670
671 bool SourcePainter::IsKeyword( char* word, int wordLen )
672 {
673 check_keyword_map(0);
674
675 int rank = get_rank( word, word + wordLen );
676
677 return ( rank == RANK_BLUE || rank == RANK_RED );
678 }