Bladeren bron

Implemented py_input using Python C API and fixed uninitialised value warning.

Sander Mathijs van Veen 14 jaren geleden
bovenliggende
commit
687b4238ed
3 gewijzigde bestanden met toevoegingen van 99 en 49 verwijderingen
  1. 95 16
      src/c/bison_callback.c
  2. 2 1
      src/c/bison_callback.h
  3. 2 32
      src/pyrex/bison_.pyx

+ 95 - 16
src/c/bison_callback.c

@@ -25,15 +25,27 @@
  */
 
 #include "Python.h"
-#include "stdarg.h"
+
+#include <stdarg.h>
 #include <stdio.h>
+#include <string.h>
 
 #define likely(x)       __builtin_expect((x),1)
 #define unlikely(x)     __builtin_expect((x),0)
 
+static PyObject *py_callback_hook_handler_name;
+static PyObject *py_callback_hook_read_after_name;
+static PyObject *py_callback_hook_read_before_name;
+
 static PyObject *py_callback_handle_name;
-static PyObject *py_callback_hook_name;
+static PyObject *py_callback_read_name;
 
+// Construct attribute names (only the first time)
+// TODO: where do we Py_DECREF(handle_name) ??
+#define INIT_ATTR(variable, name) \
+    if (unlikely(!variable)) { \
+        variable = PyString_FromString(name); \
+    }
 
 /*
  * Callback function which is invoked by target handlers within the C yyparse()
@@ -66,24 +78,16 @@ PyObject* py_callback(PyObject *parser, char *target, int option, int nargs,
 
     va_end(ap);
 
-    // Construct attribute names (only the first time)
-    if (unlikely(!py_callback_handle_name)) {
-        py_callback_handle_name = PyString_FromString("_handle");
-        // TODO: where do we Py_DECREF(handle_name) ??
-    }
-
-    if (unlikely(!py_callback_hook_name)) {
-        py_callback_hook_name = PyString_FromString("hook_handler");
-        // TODO: where do we Py_DECREF(hook_name) ??
-    }
+    INIT_ATTR(py_callback_handle_name, "_handle");
+    INIT_ATTR(py_callback_hook_handler_name, "hook_handler");
 
     // Call the handler with the arguments
     PyObject *handle = PyObject_GetAttr(parser, py_callback_handle_name);
 
-    if (unlikely(!handle)) return res;
+    if (unlikely(!handle)) return NULL;
 
     PyObject *arglist = Py_BuildValue("(siOO)", target, option, names, values);
-    if (unlikely(!arglist)) { Py_DECREF(handle); return res; }
+    if (unlikely(!arglist)) { Py_DECREF(handle); return NULL; }
 
     res = PyObject_CallObject(handle, arglist);
 
@@ -93,10 +97,10 @@ PyObject* py_callback(PyObject *parser, char *target, int option, int nargs,
     if (unlikely(!res)) return res;
 
     // Check if the "hook_handler" callback exists
-    if (unlikely(!PyObject_HasAttr(parser, py_callback_hook_name)))
+    if (unlikely(!PyObject_HasAttr(parser, py_callback_hook_handler_name)))
         return res;
 
-    handle = PyObject_GetAttr(parser, py_callback_hook_name);
+    handle = PyObject_GetAttr(parser, py_callback_hook_handler_name);
 
     if (unlikely(!handle)) {
         Py_DECREF(res);
@@ -114,3 +118,78 @@ PyObject* py_callback(PyObject *parser, char *target, int option, int nargs,
 
     return res;
 }
+
+void py_input(PyObject *parser, char *buf, int *result, int max_size)
+{
+    PyObject *handle, *arglist, *res;
+    char *bufstr;
+
+    INIT_ATTR(py_callback_hook_read_after_name, "hook_read_after");
+    INIT_ATTR(py_callback_hook_read_before_name, "hook_read_before");
+    INIT_ATTR(py_callback_read_name, "read");
+
+    // Check if the "hook_READ_BEFORE" callback exists
+    if (unlikely(!PyObject_HasAttr(parser, py_callback_hook_read_before_name)))
+    {
+        handle = PyObject_GetAttr(parser, py_callback_hook_read_before_name);
+        if (unlikely(!handle)) return;
+
+        // Call the "hook_READ_BEFORE" callback
+        arglist = PyTuple_New(0);
+        if (unlikely(!arglist)) { Py_DECREF(handle); return; }
+
+        res = PyObject_CallObject(handle, arglist);
+
+        Py_DECREF(handle);
+        Py_DECREF(arglist);
+    }
+
+    // Read the input string and catch keyboard interrupt exceptions.
+    handle = PyObject_GetAttr(parser, py_callback_read_name);
+    if (unlikely(!handle)) {
+        // TODO: set exception message for missing attribute error
+        return;
+    }
+
+    arglist = Py_BuildValue("(i)", max_size);
+    if (unlikely(!arglist)) { Py_DECREF(handle); return; }
+
+    res = PyObject_CallObject(handle, arglist);
+
+    Py_DECREF(handle);
+    Py_DECREF(arglist);
+
+    if (unlikely(!res)) { return; }
+
+    // Check if the "hook_read_after" callback exists
+    if (unlikely(!PyObject_HasAttr(parser, py_callback_hook_read_after_name)))
+        goto finish_input;
+
+    handle = PyObject_GetAttr(parser, py_callback_hook_read_after_name);
+    if (unlikely(!handle)) return;
+
+    // Call the "hook_READ_AFTER" callback
+    arglist = Py_BuildValue("(O)", res);
+    if (unlikely(!arglist)) { Py_DECREF(handle); return; }
+
+    res = PyObject_CallObject(handle, arglist);
+
+    Py_DECREF(handle);
+    Py_DECREF(arglist);
+
+    if (unlikely(!res)) return;
+
+finish_input:
+
+    // Copy the read python input string to the buffer
+    bufstr = PyString_AsString(res);
+    *result = strlen(bufstr);
+    memcpy(buf, bufstr, *result);
+
+    // TODO: translate the following code snippet to the Python C aPI
+    //if buflen == 0 and parser.file:
+    //    # Marks the Python file object as being closed from Python's point of
+    //    # view. This does not close the associated C stream (which is not
+    //    # necessary here, otherwise use "os.close(0)").
+    //    parser.file.close()
+}

+ 2 - 1
src/c/bison_callback.h

@@ -1,4 +1,5 @@
 #include "Python.h"
 #include "stdarg.h"
 
-PyObject* py_callback(PyObject *, char *, int option, int nargs,...);
+PyObject* py_callback(PyObject *, char *, int, int,...);
+void py_input(PyObject *, char *, int *, int);

+ 2 - 32
src/pyrex/bison_.pyx

@@ -47,7 +47,8 @@ cdef extern from "string.h":
 # Callback function which is invoked by target handlers
 # within the C yyparse() function.
 cdef extern from "../c/bison_callback.h":
-    object py_callback(object, char *, int option, int nargs,...)
+    object py_callback(object, char *, int, int,...)
+    void py_input(object, char *, int *, int)
 
 cdef extern from "../c/bisondynlib.h":
     void *bisondynlib_open(char *filename)
@@ -59,37 +60,6 @@ cdef extern from "../c/bisondynlib.h":
 
     #int bisondynlib_build(char *libName, char *includedir)
 
-# callback routine for reading input
-cdef public void py_input(object parser, char *buf, int *result, int max_size):
-    cdef int buflen
-
-    if parser.verbose:
-        print '\npy_input: want to read up to %s bytes' % max_size
-
-    if hasattr(parser, 'hook_read_before'):
-        parser.hook_read_before()
-
-    try:
-        raw = parser.read(max_size)
-    except KeyboardInterrupt:
-        raw = ''
-
-    if hasattr(parser, 'hook_read_after'):
-        raw = parser.hook_read_after(raw)
-
-    buflen = PyInt_AsLong(len(raw))
-    result[0] = buflen
-    memcpy(buf, PyString_AsString(raw), buflen)
-
-    if parser.verbose:
-        print '\npy_input: got %s bytes' % buflen
-
-    if buflen == 0 and parser.file:
-        # Marks the Python file object as being closed from Python's point of
-        # view. This does not close the associated C stream (which is not
-        # necessary here, otherwise use "os.close(0)").
-        parser.file.close()
-
 
 import sys, os, sha, re, imp, traceback
 import shutil