@@ -210,23 +210,37 @@ class CheckedFunction(Function):
210210 def __init__(self, *a, **kw):
211211 super(CheckedFunction, self).__init__(*a, **kw)
212212 self._failure_expression = kw.get('failure_expression', '')
213+ self._failure_cleanup = kw.get('failure_cleanup', '')
213214
214215 def set_failure_expression(self, expr):
215216 self._failure_expression = expr
216217
218+ def set_failure_cleanup(self, expr):
219+ self._failure_cleanup = expr
220+
217221 def generate_call(self):
218222 super(CheckedFunction, self).generate_call()
219223 check = "PyErr_Occurred()"
220224 if self._failure_expression:
221225 check = "{} && {}".format(self._failure_expression, check)
222- self.before_call.write_error_check(check)
226+ failure_cleanup = self._failure_cleanup or None
227+ self.before_call.write_error_check(check, failure_cleanup)
223228
224229def add_checked_function(mod, name, retval, params, failure_expression='', *a, **kw):
225230 fn = CheckedFunction(name, retval, params, *a, **kw)
226231 fn.set_failure_expression(failure_expression)
227232 mod._add_function_obj(fn)
228233 return fn
229234
235+ def add_checked_string_function(mod, name, retval, params, failure_expression='', *a, **kw):
236+ fn = CheckedFunction(name, retval, params, *a, **kw)
237+ cleanup = 'free(retval);'
238+ fn.set_failure_cleanup(cleanup)
239+ fn.after_call.add_cleanup_code(cleanup)
240+ fn.set_failure_expression(failure_expression)
241+ mod._add_function_obj(fn)
242+ return fn
243+
230244mod = Module('_%[1]s')
231245mod.add_include('"%[1]s_go.h"')
232246mod.add_function('GoPyInit', None, [])
@@ -351,8 +365,6 @@ build:
351365 # use pybindgen to build the %[1]s.c file which are the CPython wrappers to cgo wrappers..
352366 # note: pip install pybindgen to get pybindgen if this fails
353367 $(PYTHON) build.py
354- # patch storage leaks in pybindgen output
355- go run patch-leaks.go %[1]s.c
356368 # build the _%[1]s$(LIBEXT) library that contains the cgo and CPython wrappers
357369 # generated %[1]s.py python wrapper imports this c-code package
358370 $(GCC) %[1]s.c %[6]s %[1]s_go$(LIBEXT) -o _%[1]s$(LIBEXT) $(CFLAGS) $(LDFLAGS) -fPIC --shared -w
@@ -394,91 +406,11 @@ build:
394406 # use pybindgen to build the %[1]s.c file which are the CPython wrappers to cgo wrappers..
395407 # note: pip install pybindgen to get pybindgen if this fails
396408 $(PYTHON) build.py
397- # patch storage leaks in pybindgen output
398- go run patch-leaks.go %[1]s.c
399409 # build the executable
400410 - rm %[1]s_go$(LIBEXT)
401411 $(GOBUILD) -o py%[1]s
402412
403413`
404-
405- patchLeaksPreamble = `// patch-leaks.go for post-processing %[1]s.
406- // File is generated by gopy. Do not edit.
407- // %[2]s
408- // +build ignore
409-
410- package main
411-
412- import (
413- "bufio"
414- "bytes"
415- "io/ioutil"
416- "log"
417- "os"
418- "strings"
419- )
420-
421- const (
422- cStringLine = " py_retval = Py_BuildValue((char *) \"s\", retval);"
423- )
424- var cstringFunctions = []string{
425- `
426-
427- patchLeaksPostamble = `
428- }
429-
430- func isCString(line string, names []string) bool {
431- for _, cfn := range names {
432- if strings.HasPrefix(line, cfn) {
433- return true
434- }
435- }
436- return false
437- }
438-
439- func patchCString(line string, out *bytes.Buffer) bool {
440- out.WriteString(line)
441- out.Write([]byte{'\n'})
442- switch line {
443- case "}":
444- return false
445- case cStringLine:
446- out.WriteString(" free(retval);\n")
447- return false
448- }
449- return true
450- }
451-
452- func main() {
453- file := os.Args[1]
454- buf, err := ioutil.ReadFile(file)
455- if err != nil {
456- log.Fatal(err)
457- }
458- sc := bufio.NewScanner(bytes.NewBuffer(buf))
459- obuf := &bytes.Buffer{}
460- var cstring bool
461- for sc.Scan() {
462- line := sc.Text()
463- if cstring {
464- cstring = patchCString(line, obuf)
465- continue
466- }
467- cstring = isCString(line, cstringFunctions)
468- obuf.WriteString(line)
469- obuf.Write([]byte{'\n'})
470- }
471-
472- if err := sc.Err(); err != nil {
473- log.Fatal(err)
474- }
475-
476- err = ioutil.WriteFile(file, obuf.Bytes(), 0644)
477- if err != nil {
478- log.Fatal(err)
479- }
480- }
481- `
482414)
483415
484416// thePyGen is the current pyGen which is needed in symbols to lookup
@@ -570,7 +502,6 @@ func (g *pyGen) genPre() {
570502 g .makefile = & printer {buf : new (bytes.Buffer ), indentEach : []byte ("\t " )}
571503 }
572504 g .genGoPreamble ()
573- g .genLeaksPreamble ()
574505 g .genPyBuildPreamble ()
575506 if ! NoMake {
576507 g .genMakefile ()
@@ -593,9 +524,7 @@ func (g *pyGen) genPrintOut(outfn string, pr *printer) {
593524func (g * pyGen ) genOut () {
594525 g .pybuild .Printf ("\n mod.generate(open('%v.c', 'w'))\n \n " , g .cfg .Name )
595526 g .gofile .Printf ("\n \n " )
596- g .genLeaksPostamble ()
597527 g .genPrintOut (g .cfg .Name + ".go" , g .gofile )
598- g .genPrintOut ("patch-leaks.go" , g .leakfile )
599528 g .genPrintOut ("build.py" , g .pybuild )
600529 if ! NoMake {
601530 g .makefile .Printf ("\n \n " )
@@ -669,14 +598,6 @@ func (g *pyGen) genGoPreamble() {
669598 g .gofile .Printf ("\n // --- generated code for package: %[1]s below: ---\n \n " , g .cfg .Name )
670599}
671600
672- func (g * pyGen ) genLeaksPreamble () {
673- g .leakfile .Printf (patchLeaksPreamble , g .cfg .Name , g .cfg .Cmd )
674- }
675-
676- func (g * pyGen ) genLeaksPostamble () {
677- g .leakfile .Printf (patchLeaksPostamble )
678- }
679-
680601func (g * pyGen ) genPyBuildPreamble () {
681602 g .pybuild .Printf (PyBuildPreamble , g .cfg .Name , g .cfg .Cmd )
682603}
0 commit comments