Skip to content

Commit e0d7f78

Browse files
committed
Fix the const_cast problem.
The boost::python::str constructor accepts only a const char* and a non-const simply doesn't cut it. However, I felt putting const_cast's everywhere in the code was just plain ugly. This is the solution I came up with. I've also normalized the spacing between the functions in the python script. It's not made to offend, but I guess my the OCD in me felt very uncomfortable dealing with that. Signed-off-by: Jocelyn Legault <jocelynlegault@gmail.com>
1 parent 4c71655 commit e0d7f78

3 files changed

Lines changed: 132 additions & 220 deletions

File tree

PythonScript/src/CreateWrapper.py

Lines changed: 49 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -36,26 +36,25 @@
3636
'cells' : 'ScintillaCells',
3737
'colour' : 'boost::python::tuple',
3838
'keymod' : 'int' # Temporary hack - need this to be a real type
39-
}
39+
}
4040

4141
castsL = {
4242
'boost::python::str' : lambda name: "reinterpret_cast<LPARAM>(static_cast<const char*>(boost::python::extract<const char *>(" + name + ")))",
4343
# Hack - assume a tuple is a colour
4444
'boost::python::tuple': lambda name: "MAKECOLOUR(" + name + ")".format(name)
45-
}
46-
45+
}
46+
4747
castsW = {
4848
'boost::python::str' : lambda name: "reinterpret_cast<WPARAM>(static_cast<const char*>(boost::python::extract<const char *>(" + name + ")))",
4949
# Hack - assume a tuple is a colour
5050
'boost::python::tuple': lambda name: "MAKECOLOUR(" + name + ")".format(name)
51-
}
52-
51+
}
52+
5353
castsRet = {
5454
'bool' : lambda val: 'return 0 != (' + val + ')',
5555
'boost::python::tuple': lambda val: 'int retVal = callScintilla(' + val + ');\n\treturn boost::python::make_tuple(COLOUR_RED(retVal), COLOUR_GREEN(retVal), COLOUR_BLUE(retVal))'
56-
57-
}
58-
56+
}
57+
5958
# Must be kept in sync with pythonTypeExplosions
6059
typeExplosions = {
6160
#'colour' : lambda name: 'int {0}Red, int {0}Green, int {0}Blue'.format(name),
@@ -90,19 +89,14 @@ def castReturn(ty, val):
9089
def cellsBody(v, out):
9190
out.write("\treturn callScintilla(" + symbolName(v) + ", " + v["Param2Name"] + ".length(), reinterpret_cast<LPARAM>(" + v["Param2Name"] + ".cells()));\n")
9291

93-
9492
def constString(v, out):
9593
out.write("\tconst char *raw = boost::python::extract<const char *>(" + v["Param2Name"] + ".attr(\"__str__\")());\n")
9694
out.write("\treturn callScintilla(" + symbolName(v) + ", len(" + v["Param2Name"] + "), reinterpret_cast<LPARAM>(raw));\n");
9795

9896
def retString(v, out):
99-
out.write("\tint resultLength = callScintilla(" + symbolName(v) + ");\n")
100-
out.write("\tchar *result = new char[resultLength + 1];\n")
101-
out.write("\tcallScintilla(" + symbolName(v) + ", resultLength + 1, reinterpret_cast<LPARAM>(result));\n")
102-
out.write("\tresult[resultLength] = '\\0';\n")
103-
out.write("\tboost::python::str o = boost::python::str(const_cast<const char *>(result));\n")
104-
out.write("\tdelete [] result;\n")
105-
out.write("\treturn o;\n")
97+
out.write("\tPythonCompatibleStrBuffer result(callScintilla(" + symbolName(v) + ") + 1);\n")
98+
out.write("\tcallScintilla(" + symbolName(v) + ", result.size(), reinterpret_cast<LPARAM>(*result));\n")
99+
out.write("\treturn boost::python::str(result.c_str());\n")
106100

107101
def getLineBody(v, out):
108102
out.write("\tint lineCount = callScintilla(SCI_GETLINECOUNT);\n")
@@ -112,29 +106,23 @@ def getLineBody(v, out):
112106
out.write("\t}\n")
113107
out.write("\telse\n")
114108
out.write("\t{\n")
115-
out.write("\t\tint resultLength = callScintilla(" + symbolName(v) + ", line);\n")
116-
out.write("\t\tchar *result = new char[resultLength + 1];\n")
117-
out.write("\t\tcallScintilla(" + symbolName(v) + ", line, reinterpret_cast<LPARAM>(result));\n")
118-
out.write("\t\tresult[resultLength] = '\\0';\n")
119-
out.write("\t\tboost::python::str o = boost::python::str((const char *)result);\n")
120-
out.write("\t\tdelete [] result;\n")
121-
out.write("\t\treturn o;\n")
109+
out.write("\t\tPythonCompatibleStrBuffer result(callScintilla(SCI_LINELENGTH, line) + 1);\n")
110+
out.write("\t\tcallScintilla(" + symbolName(v) + ", line, reinterpret_cast<LPARAM>(*result));\n")
111+
out.write("\t\treturn boost::python::str(result.c_str());\n")
122112
out.write("\t}\n")
123113

124-
125114
def retStringNoLength(v, out):
126-
out.write("\tint resultLength = callScintilla(" + symbolName(v))
115+
out.write("\tPythonCompatibleStrBuffer result(callScintilla(" + symbolName(v))
127116
if v["Param1Type"] != '' or v["Param2Type"] != '':
128117
out.write(", ")
129118
if v["Param1Type"] != '':
130119
out.write(v["Param1Name"]);
131-
120+
132121
if v["Param2Type"] != '':
133122
out.write(v["Param2Name"]);
123+
124+
out.write("));\n")
134125

135-
out.write(");\n")
136-
137-
out.write("\tchar *result = new char[resultLength + 1];\n")
138126
out.write("\tcallScintilla(" + symbolName(v) + ", ")
139127

140128
if v["Param1Type"] or v["Param2Type"]:
@@ -144,13 +132,9 @@ def retStringNoLength(v, out):
144132
out.write(v["Param2Name"]);
145133
else:
146134
out.write("0");
147-
148-
149-
out.write(", reinterpret_cast<LPARAM>(result));\n")
150-
out.write("\tresult[resultLength] = '\\0';\n")
151-
out.write("\tboost::python::str o = boost::python::str(const_cast<const char *>(result));\n")
152-
out.write("\tdelete [] result;\n")
153-
out.write("\treturn o;\n")
135+
136+
out.write(", reinterpret_cast<LPARAM>(*result));\n")
137+
out.write("\treturn boost::python::str(result.c_str());\n")
154138

155139
def findTextBody(v, out):
156140
out.write('\tSci_TextToFind src;\n')
@@ -162,7 +146,6 @@ def findTextBody(v, out):
162146
out.write('\t{\n\t\treturn boost::python::object();\n\t}\n')
163147
out.write('\telse\n\t{\n\t\treturn boost::python::make_tuple(src.chrgText.cpMin, src.chrgText.cpMax);\n\t}\n')
164148

165-
166149
def getTextRangeBody(v, out):
167150
out.write('\tSci_TextRange src;\n')
168151
out.write('\tif (end < start)\n')
@@ -171,15 +154,13 @@ def getTextRangeBody(v, out):
171154
out.write('\t\tstart = end;\n')
172155
out.write('\t\tend = temp;\n')
173156
out.write('\t}\n')
157+
out.write("\tPythonCompatibleStrBuffer result((end-start) + 1);\n")
174158
out.write('\tsrc.chrg.cpMin = start;\n')
175159
out.write('\tsrc.chrg.cpMax = end;\n')
176-
out.write('\tsrc.lpstrText = new char[(end-start) + 1];\n')
160+
out.write('\tsrc.lpstrText = *result;\n')
177161
out.write('\tcallScintilla({0}, 0, reinterpret_cast<LPARAM>(&src));\n'.format(symbolName(v)))
178-
out.write('\tboost::python::str ret(const_cast<const char*>(src.lpstrText));\n')
179-
out.write('\tdelete [] src.lpstrText;\n')
180-
out.write('\treturn ret;\n')
162+
out.write('\treturn boost::python::str(result.c_str());\n')
181163

182-
183164
def getStyledTextBody(v, out):
184165
out.write('\tSci_TextRange src;\n')
185166
out.write('\tif (end < start)\n')
@@ -193,20 +174,16 @@ def getStyledTextBody(v, out):
193174
out.write('\tsrc.lpstrText = new char[((end-start) * 2) + 2];\n')
194175
out.write('\tcallScintilla({0}, 0, reinterpret_cast<LPARAM>(&src));\n'.format(symbolName(v)))
195176
out.write('\tboost::python::list styles;\n')
196-
out.write('\tchar *result = new char[(end-start) + 1];\n')
197-
out.write('\tfor(int pos = 0; pos < (end - start); pos++)\n')
177+
out.write("\tPythonCompatibleStrBuffer result((end-start) + 1);\n")
178+
out.write('\tfor(int pos = 0; pos < result.size() - 1; pos++)\n')
198179
out.write('\t{\n')
199-
out.write('\t\tresult[pos] = src.lpstrText[pos * 2];\n')
180+
out.write('\t\t(*result)[pos] = src.lpstrText[pos * 2];\n')
200181
out.write('\t\tstyles.append((int)(src.lpstrText[(pos * 2) + 1]));\n')
201182
out.write('\t}\n')
202-
out.write("\tresult[end-start] = '\\0';\n")
203-
out.write('\tboost::python::str resultStr(const_cast<const char*>(result));\n')
183+
out.write('\tboost::python::str resultStr(result.c_str());\n')
204184
out.write('\tdelete [] src.lpstrText;\n')
205-
out.write('\tdelete [] result;\n')
206185
out.write('\treturn boost::python::make_tuple(resultStr, styles);\n')
207186

208-
209-
210187
def standardBody(v, out):
211188
call = 'callScintilla(' + symbolName(v)
212189

@@ -220,16 +197,13 @@ def standardBody(v, out):
220197
call += ', ' + castLparam(v["Param2Type"], v["Param2Name"])
221198
call += ")"
222199

223-
224200
if (v["ReturnType"] != 'void'):
225201
out.write('\t')
226202
out.write(castReturn(v["ReturnType"], call))
227203
else:
228204
out.write('\t' + call)
229205

230206
out.write(";\n")
231-
232-
233207

234208
def mapType(t):
235209
return types.get(t, t)
@@ -254,7 +228,6 @@ def explodeType(ty, name):
254228
def explodePythonType(ty, name):
255229
return pythonTypeExplosions.get(ty, lambda name: name)(name)
256230

257-
258231
def writeParams(param1Type, param1Name, param2Type, param2Name):
259232
retVal = ""
260233
if param1Type:
@@ -266,7 +239,6 @@ def writeParams(param1Type, param1Name, param2Type, param2Name):
266239
retVal += explodeType(param2Type, param2Name)
267240

268241
return retVal
269-
270242

271243
def writePythonParams(param1Type, param1Name, param2Type, param2Name):
272244
retVal = ""
@@ -280,7 +252,6 @@ def writePythonParams(param1Type, param1Name, param2Type, param2Name):
280252

281253
return retVal
282254

283-
284255
argumentMap = {
285256
# (firstParamType, firstParamName, secondParamType, secondParamName) : ( returnType, FirstParamType, SecondParamType, bodyFunction)
286257
('int', 'length', 'string', '') : ('int', '', 'boost::python::object', constString),
@@ -290,7 +261,6 @@ def writePythonParams(param1Type, param1Name, param2Type, param2Name):
290261
('int', 'length', 'cells', '') : ('int', '', 'ScintillaCells', cellsBody),
291262
('int', '', 'findtext', 'ft') : ('boost::python::object', 'int', 'findtext', findTextBody),
292263
('', '', 'textrange', 'tr') : ('boost::python::str', '', 'textrange', getTextRangeBody)
293-
294264
}
295265

296266
specialCases = {
@@ -307,7 +277,6 @@ def getSignature(v):
307277
def formatPythonName(name):
308278
return name[0:1].lower() + name[1:]
309279

310-
311280
def getPythonSignature(v):
312281
sig = "{0}(".format(formatPythonName(v["Name"]))
313282

@@ -316,15 +285,33 @@ def getPythonSignature(v):
316285
if v["ReturnType"] and v["ReturnType"] != "void":
317286
sig += " -> " + v["ReturnType"].replace("boost::python::", "")
318287

319-
320288
return sig
321289

322-
323290
def writeCppFile(f,out):
324291
out.write('#include "stdafx.h"\n')
325292
out.write('#include "ScintillaWrapper.h"\n')
326293
out.write('#include "Scintilla.h"\n')
327-
out.write('\n\n')
294+
out.write('\n')
295+
out.write('// Helper class\n')
296+
out.write('class PythonCompatibleStrBuffer\n')
297+
out.write('{\n')
298+
out.write('public:\n')
299+
out.write('\tinline PythonCompatibleStrBuffer(int length) :\n')
300+
out.write('\t\tm_bufferPtr(new char[length]),\n')
301+
out.write('\t\tm_bufferLen(length)\n')
302+
out.write('\t{\n')
303+
out.write('\t\tm_bufferPtr[length-1] = \'\\0\';\n')
304+
out.write('\t}\n')
305+
out.write('\tinline ~PythonCompatibleStrBuffer() { delete [] m_bufferPtr; }\n')
306+
out.write('\tinline char* operator*() const { return m_bufferPtr; }\n')
307+
out.write('\tinline const char* c_str() const { return m_bufferPtr; }\n')
308+
out.write('\tinline int size() const { return m_bufferLen; }\n')
309+
out.write('private:\n')
310+
out.write('\tPythonCompatibleStrBuffer(); // default constructor disabled\n')
311+
out.write('\tchar* m_bufferPtr;\n')
312+
out.write('\tint m_bufferLen;\n')
313+
out.write('};\n')
314+
out.write('\n')
328315

329316
for name in f.order:
330317
v = f.features[name]
@@ -357,9 +344,6 @@ def writeCppFile(f,out):
357344
body(v, out)
358345
out.write("}\n\n")
359346

360-
361-
362-
363347
def writeHFile(f,out):
364348
for name in f.order:
365349
v = f.features[name]
@@ -387,7 +371,6 @@ def writeHFile(f,out):
387371
out.write("\t");
388372
out.write(getSignature(v).replace(' ScintillaWrapper::', ' '))
389373
out.write(";\n\n")
390-
391374

392375
def writeBoostWrapFile(f,out):
393376
for name in f.order:
@@ -445,8 +428,6 @@ def writeEnumsHFile(f, out):
445428
join = ","
446429
out.write("\n};\n")
447430

448-
449-
450431
def writeEnumsWrapperFile(f, out):
451432
for name in f.enums:
452433
v = f.enums[name]
@@ -473,7 +454,7 @@ def writeEnumsWrapperFile(f, out):
473454
out.write('\n\t\t.value("SCI_{0}", PYSCR_SCI_{1})'.format(name.upper(), name.upper()))
474455

475456
out.write(';\n\n')
476-
457+
477458
def writeScintillaDoc(f, out):
478459
oldCat = ""
479460

@@ -508,7 +489,6 @@ def writeScintillaDoc(f, out):
508489
out.write("\n\n ")
509490
out.write("\n ".join(v["Comment"]))
510491
out.write("\n\n See Scintilla documentation for `{0} <http://www.scintilla.org/ScintillaDoc.html#{0}>`_\n\n".format(symbolName(v)))
511-
512492

513493
def writeScintillaEnums(f, out):
514494
out.write("\n\n")
@@ -521,16 +501,12 @@ def writeScintillaEnums(f, out):
521501
for val in v['Values']:
522502
out.write('.. attribute:: {0}.{1}\n\n'.format(name.upper(), val[0][len(v['Value']):].upper()))
523503

524-
525-
526-
527504
def findEnum(f, name):
528505
for e in f.enums:
529506
l = len(f.enums[e]["Value"])
530507
if f.enums[e]["Value"] == name[:l]:
531508
return e
532509
return None
533-
534510

535511
def findEnumValues(f):
536512
f.enums = {}
@@ -545,13 +521,10 @@ def findEnumValues(f):
545521
if v["FeatureType"] == 'val':
546522
enum = findEnum(f, name)
547523

548-
549524
if enum is not None:
550525
if f.enums[enum].get("Values", None) == None:
551526
f.enums[enum]["Values"] = []
552527
f.enums[enum]["Values"] += [(name, v["Value"])]
553-
554-
555528

556529
def CopyWithInsertion(input, output, genfn, definition):
557530
copying = 1

PythonScript/src/ScintillaWrapper.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2568,7 +2568,6 @@ class ScintillaWrapper : public NppPythonScript::PyProducerConsumer<CallbackExec
25682568
callbackT m_callbacks;
25692569

25702570
bool m_notificationsEnabled;
2571-
25722571

25732572
static void runCallbacks(CallbackExecArgs *args);
25742573
};

0 commit comments

Comments
 (0)