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