1 /**********************************************************************
2 *
3 * SWIG Foreign Function Interface (FFI) definition for the Link Grammar
4 * shared (dynamic) library.
5 *
6 ***********************************************************************/
7 %module clinkgrammar
8 %{
9 
10 #include <link-grammar/link-includes.h>
11 
12 %}
13 
14 %nodefaultdtor lg_errinfo;
15 
16 #define link_public_api(x) x
17 #ifndef bool                         /* Prevent syntax errors if no bool. */
18 #define bool int
19 #endif /* bool */
20 
21 %newobject dictionary_get_data_dir;
22 
23 /**********************************************************************
24 *
25 * Functions that create and manipulate Linkages.
26 * When a Linkage is requested, the user is given a
27 * copy of all of the necessary information, and is responsible
28 * for freeing up the storage when he/she is finished, using
29 * the routines provided below.
30 *
31 ***********************************************************************/
32 
33 /**********************************************************************
34 *
35 * These functions allocate strings to be returned, so need to be
36 * newobject'd to avoid memory leaks
37 *
38 ***********************************************************************/
39 
40 %newobject linkage_print_diagram;
41 %typemap(newfree) char * {
42    linkage_free_diagram($1);
43 }
44 %rename("%s") linkage_print_diagram;
45 
46 %newobject linkage_print_postscript;
47 %typemap(newfree) char * {
48    linkage_free_postscript($1);
49 }
50 %rename("%s")  linkage_print_postscript;
51 
52 %newobject linkage_print_links_and_domains;
53 %typemap(newfree) char * {
54    linkage_free_links_and_domains($1);
55 }
56 %rename("%s")  linkage_print_links_and_domains;
57 
58 %newobject linkage_print_constituent_tree;
59 %typemap(newfree) char * {
60    linkage_free_constituent_tree_str($1);
61 }
62 %rename("%s")  linkage_print_constituent_tree;
63 
64 %newobject linkage_print_disjuncts;
65 %typemap(newfree) char * {
66    linkage_free_disjuncts($1);
67 }
68 %rename("%s")  linkage_print_disjuncts;
69 
70 %typemap(newfree) char * {
71    linkage_free_pp_msgs($1);
72 }
73 %rename("%s")  linkage_print_pp_msgs;
74 
75 // Reset to default.
76 %typemap(newfree) char * {
77    free($1);
78 }
79 
80 /* Error-handling facility calls. */
81 %rename(_lg_error_formatmsg) lg_error_formatmsg;
82 %newobject lg_error_formatmsg;
83 %rename(_prt_error) prt_error;
84 /* For security, the first argument should always contain a single "%s"
85  * (e.g. "%s\n"), and the second one should always be a C string. */
86 int prt_error(const char *, const char *);
87 
88 /*
89  * A wrapper to this function is complex and is not implemented here.  However,
90  * such a wrapper may not be needed anyway since this function is provided
91  * mainly for the low-level implementation of the error callback, so bound
92  * languages can free the memory of the callback data.
93  */
94 %ignore lg_error_set_handler_data;
95 
96 // Set a default newfree typemap.
97 %typemap(newfree) char * {
98    free($1);
99 }
100 
101 %immutable;                          /* Future-proof for const definitions. */
102 %include ../link-grammar/link-includes.h
103 %mutable;
104 
105 #ifdef SWIGPYTHON
106 %extend lg_errinfo
107 {
108     %pythoncode
109     %{
110         def formatmsg(self):
111             return _lg_error_formatmsg(self)
112         __swig_destroy__ = _clinkgrammar.delete_lg_errinfo
113         __del__ = lambda self: None
114     %}
115 }
116 
117 %{
118 static lg_error_handler default_error_handler;
119 
120 static lg_errinfo *dup_lg_errinfo(lg_errinfo *lge)
121 {
122    lg_errinfo *mlge = (lg_errinfo *)malloc(sizeof(lg_errinfo));
123    mlge->severity_label = strdup(lge->severity_label);
124    mlge->text = strdup(lge->text);
125    mlge->severity = lge->severity;
126 
127    return mlge;
128 }
129 
130 /**
131  * This function is installed as the C error callback when an error callback
132  * is set by the Python code to a Python function (but not when set to None
133  * or to the library default error handler).
134  * When invoked by the LG library, it calls the Python function along with
135  * its data. Both appear in func_and_data, which is a Python tuple of 2
136  * elements - a function and an arbitrary data object.
137 */
138 static void PythonCallBack(lg_errinfo *lge, void *func_and_data)
139 {
140    lg_errinfo *mlgep = dup_lg_errinfo(lge);
141    PyObject *pylge = SWIG_NewPointerObj(SWIG_as_voidptr(mlgep),
142                                        SWIGTYPE_p_lg_errinfo, SWIG_POINTER_OWN);
143    PyObject *func = PyTuple_GetItem((PyObject *)func_and_data, 0);
144    PyObject *data = PyTuple_GetItem((PyObject *)func_and_data, 1);
145 
146    PyObject *args = Py_BuildValue("OO", pylge, data);
147    PyObject *rc = PyEval_CallObject(func, args); /* Py LG error cb. */
148 
149    Py_DECREF(pylge);
150    Py_DECREF(args);
151    if (NULL == rc)
152        PyErr_Print();
153    Py_XDECREF(rc);
154 }
155 %}
156 
157 %typemap(in) lg_errinfo *eh_lge
158 {
159    void *argp1 = 0;
160 
161    if (Py_None == $input)
162       SWIG_exception_fail(SWIG_TypeError, "in method '_py_error_default_handler', argument 1 (of type lg_errinfo *) must not be None.");
163 
164    int res1 = SWIG_ConvertPtr($input, &argp1, SWIGTYPE_p_lg_errinfo, 0);
165    if (!SWIG_IsOK(res1)) {
166       SWIG_exception_fail(SWIG_ArgError(res1), "in method '_py_error_default_handler', argument 1 of type 'lg_errinfo *'");
167    }
168    arg1 = (lg_errinfo *)(argp1);
169 }
170 
171 /* The second argument of the default callback can be NULL or
172    a severity_level integer. Validate that and convert it to C int. */
173 %typemap(in) int *pedh_data (int arg)
174 {
175    bool error = false;
176    const char errmsg[] = "The default error handler data argument (arg 2) "
177                          "must be an integer (0 to lg_None) or None.";
178 
179    if (Py_None == $input)
180    {
181       $1 = NULL;
182    }
183    else
184    {
185       if (!PyInt_Check($input))
186       {
187          SWIG_exception_fail(SWIG_TypeError, errmsg);
188          error = true;
189       }
190       else
191       {
192           arg = (int)PyInt_AsLong($input);
193       }
194 
195       if ((arg < 0) || (arg > lg_None))
196       {
197          SWIG_exception_fail(SWIG_ValueError, errmsg);
198          error = true;
199       }
200 
201       if (error) return NULL;
202       $1 = &arg;
203    }
204 }
205 
206 %inline %{
207 void _py_error_default_handler(lg_errinfo *eh_lge, int *pedh_data)
208 {
209     default_error_handler(eh_lge, (void *)pedh_data);
210 }
211 
212 /**
213  * Set a Python function/data as the LG error handler callback.
214  * Note that because the LG library cannot directly call a Python function,
215  * the actual callback function is a C proxy function PythonCallBack() and
216  * the Python function/data is set as the C callback data.
217  */
218 PyObject *_py_error_set_handler(PyObject *func_and_data)
219 {
220    const void *old_func_and_data = lg_error_set_handler_data(NULL);
221    PyObject *func = PyTuple_GetItem((PyObject *)func_and_data, 0);
222    lg_error_handler old_handler;
223 
224    if (Py_None == func)
225    {
226       old_handler = lg_error_set_handler(NULL, NULL);
227    }
228    else
229    {
230       if (!PyCallable_Check(func)) {
231           PyErr_SetString(PyExc_TypeError, "Argument 1 must be callable");
232           return NULL;
233       }
234       old_handler = lg_error_set_handler(PythonCallBack, func_and_data);
235       Py_INCREF(func_and_data);
236    }
237 
238    if (NULL == (PyObject *)old_handler)
239       Py_RETURN_NONE;
240 
241    if (PythonCallBack == old_handler)
242    {
243       func = PyTuple_GetItem((PyObject *)old_func_and_data, 0);
244       Py_INCREF(func);
245       Py_XDECREF(old_func_and_data);
246       return func;
247    }
248 
249    /* This must be the first call. Grab the C default error handler. */
250    default_error_handler = old_handler;
251 
252    /* Signify this is the default error handler by a string object. */
253    return Py_BuildValue("s", "");
254 }
255 
256 PyObject *_py_error_printall(PyObject *func_and_data)
257 {
258    Py_INCREF(func_and_data);
259    int n = lg_error_printall(PythonCallBack, func_and_data);
260    Py_DECREF(func_and_data);
261 
262    PyObject *py_n = PyInt_FromLong(n);
263    return py_n;
264 }
265 
266 void delete_lg_errinfo(lg_errinfo *lge) {
267   if (NULL == lge) return; /* Was None - nothing to free. */
268   free((void *)lge->severity_label);
269   free((void *)lge->text);
270   free((void *)lge);
271 }
272 
273 /**
274  * incref/decref a Python object.
275  * Currently used on the Dictionary object when a Sentence object is created/deleted,
276  * because the Sentence object includes a reference to the Dictionary structure.
277  */
278 void _py_incref(PyObject *x)
279 {
280   Py_INCREF(x);
281 }
282 
283 void _py_decref(PyObject *x)
284 {
285   Py_DECREF(x);
286 }
287 %}
288 #endif /* SWIGPYTHON */
289