fixed the last of the off-by-one errors (some are refixed, again...)
[wxWidgets.git] / src / stc / gen_iface.py
1 #!/bin/env python
2 #----------------------------------------------------------------------------
3 # Name: gen_iface.py
4 # Purpose: Generate stc.h and stc.cpp from the info in Scintilla.iface
5 #
6 # Author: Robin Dunn
7 #
8 # Created: 5-Sept-2000
9 # RCS-ID: $Id$
10 # Copyright: (c) 2000 by Total Control Software
11 # Licence: wxWindows license
12 #----------------------------------------------------------------------------
13
14
15 import sys, string, re
16 from fileinput import FileInput
17
18
19 IFACE = './scintilla/include/Scintilla.iface'
20 H_TEMPLATE = './stc.h.in'
21 CPP_TEMPLATE = './stc.cpp.in'
22 H_DEST = '../../include/wx/stc/stc.h'
23 CPP_DEST = './stc.cpp'
24
25
26 # Value prefixes to convert
27 valPrefixes = [('SCI_', ''),
28 ('SC_', ''),
29 ('SCN_', None), # just toss these out...
30 ('SCEN_', None),
31 ('SCE_', ''),
32 ('SCLEX_', 'LEX_'),
33 ('SCK_', 'KEY_'),
34 ('SCFIND_', 'FIND_'),
35 ('SCWS_', 'WS_'),
36 ]
37
38 # Message function values that should have a CMD_ constant as well
39 cmdValues = [ (2300, 2350), 2011, 2013, (2176, 2180) ]
40
41
42 # Map some generic typenames to wx types, using return value syntax
43 retTypeMap = {
44 'position': 'int',
45 'string': 'wxString',
46 'colour': 'wxColour',
47 }
48
49 # Map some generic typenames to wx types, using parameter syntax
50 paramTypeMap = {
51 'position': 'int',
52 'string': 'const wxString&',
53 'colour': 'const wxColour&',
54 'keymod': 'int',
55 }
56
57 # Map of method info that needs tweaked. Either the name needs changed, or
58 # the method definition/implementation. Tuple items are:
59 #
60 # 1. New method name. None to skip the method, 0 to leave the
61 # default name.
62 # 2. Method definition for the .h file, 0 to leave alone
63 # 3. Method implementation for the .cpp file, 0 to leave alone.
64 # 4. tuple of Doc string lines, or 0 to leave alone.
65 #
66 methodOverrideMap = {
67 'AddText' : (0,
68 'void %s(const wxString& text);',
69
70 '''void %s(const wxString& text) {
71 SendMsg(%s, text.Len(), (long)text.c_str());''',
72 0),
73
74 'AddStyledText' : (0,
75 'void %s(const wxString& text);',
76
77 '''void %s(const wxString& text) {
78 SendMsg(%s, text.Len(), (long)text.c_str());''',
79 0),
80
81 'GetViewWS' : ( 'GetViewWhiteSpace', 0, 0, 0),
82 'SetViewWS' : ( 'SetViewWhiteSpace', 0, 0, 0),
83
84 'GetStyledText' : (0,
85 'wxString %s(int startPos, int endPos);',
86
87 '''wxString %s(int startPos, int endPos) {
88 wxString text;
89 int len = endPos - startPos;
90 if (!len) return "";
91 TextRange tr;
92 tr.lpstrText = text.GetWriteBuf(len*2);
93 tr.chrg.cpMin = startPos;
94 tr.chrg.cpMax = endPos;
95 SendMsg(%s, 0, (long)&tr);
96 text.UngetWriteBuf(len*2);
97 return text;''',
98
99 ('Retrieve a buffer of cells.',)),
100
101
102 'PositionFromPoint' : (0,
103 'int %s(wxPoint pt);',
104
105 '''int %s(wxPoint pt) {
106 return SendMsg(%s, pt.x, pt.y);''',
107
108 0),
109
110 'GetCurLine' : (0,
111 'wxString %s(int* OUTPUT=NULL);',
112
113 '''wxString %s(int* linePos) {
114 wxString text;
115 int len = LineLength(GetCurrentLine());
116 if (!len) return "";
117 char* buf = text.GetWriteBuf(len);
118
119 int pos = SendMsg(%s, len, (long)buf);
120 text.UngetWriteBuf(len);
121 if (linePos) *linePos = pos;
122
123 return text;''',
124
125 0),
126
127 'SetUsePalette' : (None, 0,0,0),
128
129 'MarkerSetFore' : ('MarkerSetForeground', 0, 0, 0),
130 'MarkerSetBack' : ('MarkerSetBackground', 0, 0, 0),
131
132 'MarkerDefine' : (0,
133 '''void %s(int markerNumber, int markerSymbol,
134 const wxColour& foreground = wxNullColour,
135 const wxColour& background = wxNullColour);''',
136
137 '''void %s(int markerNumber, int markerSymbol,
138 const wxColour& foreground,
139 const wxColour& background) {
140
141 SendMsg(%s, markerNumber, markerSymbol);
142 if (foreground.Ok())
143 MarkerSetForeground(markerNumber, foreground);
144 if (background.Ok())
145 MarkerSetBackground(markerNumber, background);''',
146
147 ('Set the symbol used for a particular marker number,',
148 'and optionally the for and background colours.')),
149
150 'SetMarginTypeN' : ('SetMarginType', 0, 0, 0),
151 'GetMarginTypeN' : ('GetMarginType', 0, 0, 0),
152 'SetMarginWidthN' : ('SetMarginWidth', 0, 0, 0),
153 'GetMarginWidthN' : ('GetMarginWidth', 0, 0, 0),
154 'SetMarginMaskN' : ('SetMarginMask', 0, 0, 0),
155 'GetMarginMaskN' : ('GetMarginMask', 0, 0, 0),
156 'SetMarginSensitiveN' : ('SetMarginSensitive', 0, 0, 0),
157 'GetMarginSensitiveN' : ('GetMarginSensitive', 0, 0, 0),
158
159 'StyleSetFore' : ('StyleSetForeground', 0, 0, 0),
160 'StyleSetBack' : ('StyleSetBackground', 0, 0, 0),
161 'SetSelFore' : ('SetSelForeground', 0, 0, 0),
162 'SetSelBack' : ('SetSelBackground', 0, 0, 0),
163 'SetCaretFore' : ('SetCaretForeground', 0, 0, 0),
164 'StyleSetFont' : ('StyleSetFaceName', 0, 0, 0),
165
166 # need to fix this to map between wx and scintilla encoding flags, leave it out for now...
167 'StyleSetCharacterSet' : (None, 0, 0, 0),
168
169 'AssignCmdKey' : ('CmdKeyAssign',
170 'void %s(int key, int modifiers, int cmd);',
171
172 '''void %s(int key, int modifiers, int cmd) {
173 SendMsg(%s, MAKELONG(key, modifiers), cmd);''',
174
175 0),
176
177 'ClearCmdKey' : ('CmdKeyClear',
178 'void %s(int key, int modifiers);',
179
180 '''void %s(int key, int modifiers) {
181 SendMsg(%s, MAKELONG(key, modifiers));''',
182
183 0),
184
185 'ClearAllCmdKeys' : ('CmdKeyClearAll', 0, 0, 0),
186
187
188 'SetStylingEx' : ('SetStyleBytes',
189 'void %s(int length, char* styleBytes);',
190
191 '''void %s(int length, char* styleBytes) {
192 SendMsg(%s, length, (long)styleBytes);''',
193
194 0),
195
196
197 'IndicSetStyle' : ('IndicatorSetStyle', 0, 0, 0),
198 'IndicGetStyle' : ('IndicatorGetStyle', 0, 0, 0),
199 'IndicSetFore' : ('IndicatorSetForeground', 0, 0, 0),
200 'IndicGetFore' : ('IndicatorGetForeground', 0, 0, 0),
201
202 'AutoCShow' : ('AutoCompShow', 0, 0, 0),
203 'AutoCCancel' : ('AutoCompCancel', 0, 0, 0),
204 'AutoCActive' : ('AutoCompActive', 0, 0, 0),
205 'AutoCPosStart' : ('AutoCompPosStart', 0, 0, 0),
206 'AutoCComplete' : ('AutoCompComplete', 0, 0, 0),
207 'AutoCStops' : ('AutoCompStops', 0, 0, 0),
208 'AutoCSetSeparator' : ('AutoCompSetSeparator', 0, 0, 0),
209 'AutoCGetSeparator' : ('AutoCompGetSeparator', 0, 0, 0),
210 'AutoCSelect' : ('AutoCompSelect', 0, 0, 0),
211 'AutoCSetCancelAtStart' : ('AutoCompSetCancelAtStart', 0, 0, 0),
212 'AutoCGetCancelAtStart' : ('AutoCompGetCancelAtStart', 0, 0, 0),
213 'AutoCSetFillUps' : ('AutoCompSetFillUps', 0, 0, 0),
214 'AutoCSetChooseSingle' : ('AutoCompSetChooseSingle', 0, 0, 0),
215 'AutoCGetChooseSingle' : ('AutoCompGetChooseSingle', 0, 0, 0),
216 'AutoCSetIgnoreCase' : ('AutoCompSetIgnoreCase', 0, 0, 0),
217 'AutoCGetIgnoreCase' : ('AutoCompGetIgnoreCase', 0, 0, 0),
218
219 'SetHScrollBar' : ('SetUseHorizontalScrollBar', 0, 0, 0),
220 'GetHScrollBar' : ('GetUseHorizontalScrollBar', 0, 0, 0),
221
222 'GetCaretFore' : ('GetCaretForeground', 0, 0, 0),
223
224 'GetUsePalette' : (None, 0, 0, 0),
225
226 'FindText' : (0,
227 '''int %s(int minPos, int maxPos,
228 const wxString& text,
229 bool caseSensitive, bool wholeWord);''',
230 '''int %s(int minPos, int maxPos,
231 const wxString& text,
232 bool caseSensitive, bool wholeWord) {
233 TextToFind ft;
234 int flags = 0;
235
236 flags |= caseSensitive ? SCFIND_MATCHCASE : 0;
237 flags |= wholeWord ? SCFIND_WHOLEWORD : 0;
238 ft.chrg.cpMin = minPos;
239 ft.chrg.cpMax = maxPos;
240 ft.lpstrText = (char*)text.c_str();
241
242 return SendMsg(%s, flags, (long)&ft);''',
243 0),
244
245 'FormatRange' : (0,
246 '''int %s(bool doDraw,
247 int startPos,
248 int endPos,
249 wxDC* draw,
250 wxDC* target, // Why does it use two? Can they be the same?
251 wxRect renderRect,
252 wxRect pageRect);''',
253 ''' int %s(bool doDraw,
254 int startPos,
255 int endPos,
256 wxDC* draw,
257 wxDC* target, // Why does it use two? Can they be the same?
258 wxRect renderRect,
259 wxRect pageRect) {
260 RangeToFormat fr;
261
262 fr.hdc = draw;
263 fr.hdcTarget = target;
264 fr.rc.top = renderRect.GetTop();
265 fr.rc.left = renderRect.GetLeft();
266 fr.rc.right = renderRect.GetRight();
267 fr.rc.bottom = renderRect.GetBottom();
268 fr.rcPage.top = pageRect.GetTop();
269 fr.rcPage.left = pageRect.GetLeft();
270 fr.rcPage.right = pageRect.GetRight();
271 fr.rcPage.bottom = pageRect.GetBottom();
272 fr.chrg.cpMin = startPos;
273 fr.chrg.cpMax = endPos;
274
275 return SendMsg(%s, doDraw, (long)&fr);''',
276 0),
277
278
279 'GetLine' : (0,
280 'wxString %s(int line);',
281
282 '''wxString %s(int line) {
283 wxString text;
284 int len = LineLength(line);
285 if (!len) return "";
286 char* buf = text.GetWriteBuf(len);
287
288 int pos = SendMsg(%s, line, (long)buf);
289 text.UngetWriteBuf(len);
290
291 return text;''',
292
293 ('Retrieve the contents of a line.',)),
294
295 'SetSel' : ('SetSelection', 0, 0, 0),
296 'GetSelText' : ('GetSelectedText',
297 'wxString %s();',
298
299 '''wxString %s() {
300 wxString text;
301 int start;
302 int end;
303
304 GetSelection(&start, &end);
305 int len = end - start;
306 if (!len) return "";
307 char* buff = text.GetWriteBuf(len);
308
309 SendMsg(%s, 0, (long)buff);
310 text.UngetWriteBuf(len);
311 return text;''',
312
313 ('Retrieve the selected text.',)),
314
315 'GetTextRange' : (0,
316 'wxString %s(int startPos, int endPos);',
317
318 '''wxString %s(int startPos, int endPos) {
319 wxString text;
320 int len = endPos - startPos;
321 if (!len) return "";
322 char* buff = text.GetWriteBuf(len);
323 TextRange tr;
324 tr.lpstrText = buff;
325 tr.chrg.cpMin = startPos;
326 tr.chrg.cpMax = endPos;
327
328 SendMsg(%s, 0, (long)&tr);
329 text.UngetWriteBuf(len);
330 return text;''',
331
332 ('Retrieve a range of text.',)),
333
334 'PointXFromPosition' : (None, 0, 0, 0),
335 'PointYFromPosition' : (None, 0, 0, 0),
336
337 'ScrollCaret' : ('EnsureCaretVisible', 0, 0, 0),
338 'ReplaceSel' : ('ReplaceSelection', 0, 0, 0),
339 'Null' : (None, 0, 0, 0),
340
341 'GetText' : (0,
342 'wxString %s();',
343
344 '''wxString %s() {
345 wxString text;
346 int len = GetTextLength()+1;
347 char* buff = text.GetWriteBuf(len);
348
349 SendMsg(%s, len, (long)buff);
350 text.UngetWriteBuf(len-1);
351 return text;''',
352
353 ('Retrieve all the text in the document.', )),
354
355 'GetDirectFunction' : (None, 0, 0, 0),
356 'GetDirectPointer' : (None, 0, 0, 0),
357
358 'CallTipPosStart' : ('CallTipPosAtStart', 0, 0, 0),
359 'CallTipSetHlt' : ('CallTipSetHighlight', 0, 0, 0),
360 'CallTipSetBack' : ('CallTipSetBackground', 0, 0, 0),
361
362
363 # Remove all methods that are key commands since they can be
364 # executed with CmdKeyExecute
365 'LineDown' : (None, 0, 0, 0),
366 'LineDownExtend' : (None, 0, 0, 0),
367 'LineUp' : (None, 0, 0, 0),
368 'LineUpExtend' : (None, 0, 0, 0),
369 'CharLeft' : (None, 0, 0, 0),
370 'CharLeftExtend' : (None, 0, 0, 0),
371 'CharRight' : (None, 0, 0, 0),
372 'CharRightExtend' : (None, 0, 0, 0),
373 'WordLeft' : (None, 0, 0, 0),
374 'WordLeftExtend' : (None, 0, 0, 0),
375 'WordRight' : (None, 0, 0, 0),
376 'WordRightExtend' : (None, 0, 0, 0),
377 'Home' : (None, 0, 0, 0),
378 'HomeExtend' : (None, 0, 0, 0),
379 'LineEnd' : (None, 0, 0, 0),
380 'LineEndExtend' : (None, 0, 0, 0),
381 'DocumentStart' : (None, 0, 0, 0),
382 'DocumentStartExtend' : (None, 0, 0, 0),
383 'DocumentEnd' : (None, 0, 0, 0),
384 'DocumentEndExtend' : (None, 0, 0, 0),
385 'PageUp' : (None, 0, 0, 0),
386 'PageUpExtend' : (None, 0, 0, 0),
387 'PageDown' : (None, 0, 0, 0),
388 'PageDownExtend' : (None, 0, 0, 0),
389 'EditToggleOvertype' : (None, 0, 0, 0),
390 'Cancel' : (None, 0, 0, 0),
391 'DeleteBack' : (None, 0, 0, 0),
392 'Tab' : (None, 0, 0, 0),
393 'BackTab' : (None, 0, 0, 0),
394 'NewLine' : (None, 0, 0, 0),
395 'FormFeed' : (None, 0, 0, 0),
396 'VCHome' : (None, 0, 0, 0),
397 'VCHomeExtend' : (None, 0, 0, 0),
398 'ZoomIn' : (None, 0, 0, 0),
399 'ZoomOut' : (None, 0, 0, 0),
400 'DelWordLeft' : (None, 0, 0, 0),
401 'DelWordRight' : (None, 0, 0, 0),
402 'LineCut' : (None, 0, 0, 0),
403 'LineDelete' : (None, 0, 0, 0),
404 'LineTranspose' : (None, 0, 0, 0),
405 'LowerCase' : (None, 0, 0, 0),
406 'UpperCase' : (None, 0, 0, 0),
407 'LineScrollDown' : (None, 0, 0, 0),
408 'LineScrollUp' : (None, 0, 0, 0),
409
410
411 'GetDocPointer' : (0,
412 'void* %s();',
413 '''void* %s() {
414 return (void*)SendMsg(%s);''',
415 0),
416
417 'SetDocPointer' : (0,
418 'void %s(void* docPointer);',
419 '''void %s(void* docPointer) {
420 SendMsg(%s, (long)docPointer);''',
421 0),
422
423 'CreateDocument' : (0,
424 'void* %s();',
425 '''void* %s() {
426 return (void*)SendMsg(%s);''',
427 0),
428
429 'AddRefDocument' : (0,
430 'void %s(void* docPointer);',
431 '''void %s(void* docPointer) {
432 SendMsg(%s, (long)docPointer);''',
433 0),
434
435 'ReleaseDocument' : (0,
436 'void %s(void* docPointer);',
437 '''void %s(void* docPointer) {
438 SendMsg(%s, (long)docPointer);''',
439 0),
440
441 'GrabFocus' : (None, 0, 0, 0),
442
443 '' : ('', 0, 0, 0),
444
445 }
446
447 #----------------------------------------------------------------------------
448
449 def processIface(iface, h_tmplt, cpp_tmplt, h_dest, cpp_dest):
450 curDocStrings = []
451 values = []
452 methods = []
453
454 # parse iface file
455 fi = FileInput(iface)
456 for line in fi:
457 line = line[:-1]
458 if line[:2] == '##' or line == '':
459 #curDocStrings = []
460 continue
461
462 op = line[:4]
463 if line[:2] == '# ': # a doc string
464 curDocStrings.append(line[2:])
465
466 elif op == 'val ':
467 parseVal(line[4:], values, curDocStrings)
468 curDocStrings = []
469
470 elif op == 'fun ' or op == 'set ' or op == 'get ':
471 parseFun(line[4:], methods, curDocStrings, values)
472 curDocStrings = []
473
474 elif op == 'cat ':
475 if string.strip(line[4:]) == 'Deprecated':
476 break # skip the rest of the file
477
478 elif op == 'evt ':
479 pass
480
481 else:
482 print '***** Unknown line type: ', line
483
484
485 # process templates
486 data = {}
487 data['VALUES'] = processVals(values)
488 defs, imps = processMethods(methods)
489 data['METHOD_DEFS'] = defs
490 data['METHOD_IMPS'] = imps
491
492 # get template text
493 h_text = open(h_tmplt).read()
494 cpp_text = open(cpp_tmplt).read()
495
496 # do the substitutions
497 h_text = h_text % data
498 cpp_text = cpp_text % data
499
500 # write out destination files
501 open(h_dest, 'w').write(h_text)
502 open(cpp_dest, 'w').write(cpp_text)
503
504
505
506 #----------------------------------------------------------------------------
507
508 def processVals(values):
509 text = []
510 for name, value, docs in values:
511 if docs:
512 text.append('')
513 for x in docs:
514 text.append('// ' + x)
515 text.append('#define %s %s' % (name, value))
516 return string.join(text, '\n')
517
518 #----------------------------------------------------------------------------
519
520 def processMethods(methods):
521 defs = []
522 imps = []
523
524 for retType, name, number, param1, param2, docs in methods:
525 retType = retTypeMap.get(retType, retType)
526 params = makeParamString(param1, param2)
527
528 name, theDef, theImp, docs = checkMethodOverride(name, number, docs)
529
530 if name is None:
531 continue
532
533 # Build the method definition for the .h file
534 if docs:
535 defs.append('')
536 for x in docs:
537 defs.append(' // ' + x)
538 if not theDef:
539 theDef = ' %s %s(%s);' % (retType, name, params)
540 defs.append(theDef)
541
542 # Build the method implementation string
543 if docs:
544 imps.append('')
545 for x in docs:
546 imps.append('// ' + x)
547 if not theImp:
548 theImp = '%s wxStyledTextCtrl::%s(%s) {\n ' % (retType, name, params)
549
550 if retType == 'wxColour':
551 theImp = theImp + 'long c = '
552 elif retType != 'void':
553 theImp = theImp + 'return '
554 theImp = theImp + 'SendMsg(%s, %s, %s)' % (number,
555 makeArgString(param1),
556 makeArgString(param2))
557 if retType == 'bool':
558 theImp = theImp + ' != 0'
559 if retType == 'wxColour':
560 theImp = theImp + ';\n return wxColourFromLong(c)'
561
562 theImp = theImp + ';\n}'
563 imps.append(theImp)
564
565
566 return string.join(defs, '\n'), string.join(imps, '\n')
567
568
569 #----------------------------------------------------------------------------
570
571 def checkMethodOverride(name, number, docs):
572 theDef = theImp = None
573 if methodOverrideMap.has_key(name):
574 item = methodOverrideMap[name]
575
576 if item[0] != 0:
577 name = item[0]
578 if item[1] != 0:
579 theDef = ' ' + (item[1] % name)
580 if item[2] != 0:
581 theImp = item[2] % ('wxStyledTextCtrl::'+name, number) + '\n}'
582 if item[3] != 0:
583 docs = item[3]
584
585 return name, theDef, theImp, docs
586
587 #----------------------------------------------------------------------------
588
589 def makeArgString(param):
590 if not param:
591 return '0'
592
593 typ, name = param
594
595 if typ == 'string':
596 return '(long)%s.c_str()' % name
597 if typ == 'colour':
598 return 'wxColourAsLong(%s)' % name
599
600 return name
601
602 #----------------------------------------------------------------------------
603
604 def makeParamString(param1, param2):
605 def doOne(param):
606 if param:
607 aType = paramTypeMap.get(param[0], param[0])
608 return aType + ' ' + param[1]
609 else:
610 return ''
611
612 st = doOne(param1)
613 if st and param2:
614 st = st + ', '
615 st = st + doOne(param2)
616 return st
617
618
619 #----------------------------------------------------------------------------
620
621 def parseVal(line, values, docs):
622 name, val = string.split(line, '=')
623
624 # remove prefixes such as SCI, etc.
625 for old, new in valPrefixes:
626 lo = len(old)
627 if name[:lo] == old:
628 if new is None:
629 return
630 name = new + name[lo:]
631
632 # add it to the list
633 values.append( ('wxSTC_' + name, val, docs) )
634
635 #----------------------------------------------------------------------------
636
637 funregex = re.compile(r'\s*([a-zA-Z0-9_]+)' # <ws>return type
638 '\s+([a-zA-Z0-9_]+)=' # <ws>name=
639 '([0-9]+)' # number
640 '\(([ a-zA-Z0-9_]*),' # (param,
641 '([ a-zA-Z0-9_]*)\)') # param)
642
643 def parseFun(line, methods, docs, values):
644 def parseParam(param):
645 param = string.strip(param)
646 if param == '':
647 param = None
648 else:
649 param = tuple(string.split(param))
650 return param
651
652 mo = funregex.match(line)
653 if mo is None:
654 print "***** Line doesn't match! : " + line
655
656 retType, name, number, param1, param2 = mo.groups()
657
658 param1 = parseParam(param1)
659 param2 = parseParam(param2)
660
661 # Special case. For the key command functionss we want a value defined too
662 num = string.atoi(number)
663 for v in cmdValues:
664 if (type(v) == type(()) and v[0] <= num < v[1]) or v == num:
665 parseVal('CMD_%s=%s' % (string.upper(name), number), values, ())
666
667 #if retType == 'void' and not param1 and not param2:
668
669 methods.append( (retType, name, number, param1, param2, tuple(docs)) )
670
671
672 #----------------------------------------------------------------------------
673
674
675 def main(args):
676 # TODO: parse command line args to replace default input/output files???
677
678 # Now just do it
679 processIface(IFACE, H_TEMPLATE, CPP_TEMPLATE, H_DEST, CPP_DEST)
680
681
682
683 if __name__ == '__main__':
684 main(sys.argv)
685
686 #----------------------------------------------------------------------------
687
688