|
|
1 DGD extension interface
2
3 1. Introduction
4
5 DGD presents an interface for extending the driver with new kfuns and special
6 object types. To enable this interface, DGD should be compiled with the macro
7 DGD_EXTENSION defined. The driver will then call an external function at
8 initialization time:
9
10 void extension_init();
11
12 From this function, new kfuns may be added to the driver, and callback
13 functions may be set. The interface furthermore allows objects to be marked
14 as `special', associating the object with some sort of user-defined external
15 state.
16
17 The extension code must be linked with DGD at compile time. The include file
18 `dgd_ext.h' defines the entire interface with the driver, using macros that
19 all start with the prefix `DGD_'. Compliant extensions should use these
20 macros, only. Some of these macros will evaluate their arguments several
21 times; to be compatible with future releases, extensions should assume that
22 all DGD_* macros with arguments may do so.
23
24
25 2. Kernel functions
26
27 Kernel functions may be added during the initialization phase by calling the
28 following function:
29
30 void DGD_EXT_KFUN(DGD_EXTKFUN_T *kf, int n);
31
32 where `kf' is an array of DGD_EXTFUN_T structs, and `n' the number of elements
33 in that array. DGD_EXT_KFUN() should be called only once, and must not
34 redeclare any existing kfuns.
35
36 The DGD_EXTKFUN_T struct has the following fields:
37
38 char *name; /* kfun name */
39 char *proto; /* kfun prototype */
40 func; /* kfun function pointer */
41
42 Here `func' is a pointer to a C function with the following prototype:
43
44 void func(DGD_FRAME_T f, int nargs, DGD_VALUE_T *retval);
45
46 Calls to the kfun with name `name' will be routed to that C function. The
47 `f' argument contains the function context, `nargs' is the number of
48 arguments on the stack, and `retval' is a pointer to the return value. The
49 function should not attempt to push or pop arguments; instead, arguments
50 should be accessed using the relevant DGD_FRAME_* macros listed below, and the
51 return value, if any, should be stored in the retval value using one of the
52 DGD_RETVAL_* macros. The default return value is nil.
53
54 Kfuns can call DGD_ERROR() to indicate that an error happened. Errors will
55 interrupt the flow of execution, so DGD_ERROR() should be called before any
56 LPC values are constructed or changed, including the return value of the
57 kfun. Note that at present, the extension interface does not define a way to
58 call an LPC function from a kfun.
59
60 DGD_OBJECT_T DGD_FRAME_OBJECT(DGD_FRAME_T f); /* current object */
61 DGD_OBJECT_T DGD_FRAME_PROGRAM(DGD_FRAME_T f); /* current program */
62 DGD_DATA_T DGD_FRAME_DATASPACE(DGD_FRAME_T f); /* current dataspace */
63 DGD_VALUE_T DGD_FRAME_ARG(DGD_FRAME_T f, int nargs, int n);/* argument n */
64 bool DGD_FRAME_ATOMIC(DGD_FRAME_T f); /* atomic? */
65
66 void DGD_RETVAL_INT(DGD_VALUE_T *retval, DGD_INT_T num);
67 void DGD_RETVAL_FLT(DGD_VALUE_T *retval, DGD_FLOAT_T flt);
68 void DGD_RETVAL_STR(DGD_VALUE_T *retval, DGD_STRING_T str);
69 void DGD_RETVAL_OBJ(DGD_VALUE_T *retval, DGD_OBJECT_T obj);
70 void DGD_RETVAL_ARR(DGD_VALUE_T *retval, DGD_ARRAY_T arr);
71 void DGD_RETVAL_MAP(DGD_VALUE_T *retval, DGD_MAPPING_T map);
72
73 void DGD_ERROR(char *mesg);
74
75 The `proto' field of the DGD_EXTKFUN_T struct is a prototype for the function,
76 represented as a 0-terminated array of chars. For example, the LPC prototypes
77
78 string lower_case(string str);
79 string concat(string str...);
80 int foo(int *a, varargs object **b);
81 void bar(void);
82 void gnu();
83
84 would be represented as
85
86 char lower_case_proto[] = { DGD_TYPE_STRING, DGD_TYPE_STRING, 0 };
87 char concat_proto[] = { DGD_TYPE_STRING, DGD_TYPE_STRING,
88 DGD_TYPE_ELLIPSIS, 0 };
89 char foo_proto[] = { DGD_TYPE_INT, DGD_TYPE_ARRAY_OF(DGD_TYPE_INT),
90 DGD_TYPE_VARARGS,
91 DGD_TYPE_ARRAY_OF(DGD_TYPE_ARRAY_OF(DGD_TYPE_OBJECT)),
92 0 };
93 char bar_proto[] = { DGD_TYPE_VOID, DGD_TYPE_VOID, 0 };
94 char gnu_proto[] = { DGD_TYPE_VOID, 0 };
95
96 Note that the prototypes of bar() and gnu() are effectively identical, just
97 as they would be for LPC functions; also note that varargs must be specified
98 in the new way, among the arguments of the prototype rather than in front of
99 the return type.
100
101 The building blocks for prototypes are:
102
103 DGD_TYPE_VOID
104 DGD_TYPE_INT
105 DGD_TYPE_FLOAT
106 DGD_TYPE_STRING
107 DGD_TYPE_OBJECT
108 DGD_TYPE_ARRAY_OF(dgd_type)
109 DGD_TYPE_MAPPING
110 DGD_TYPE_VARARGS
111 DGD_TYPE_ELLIPSIS
112
113
114 3. Special objects
115
116 DGD defines various types of special objects: user objects, editor objects
117 and parser objects. Extensions may define their own additional special
118 object type. Special objects have an associated DGD_EINDEX_T value (normally
119 an 8-bit value), and an additional arbitrary LPC value. Furthermore,
120 user-defined special objects may have various callbacks defined for them, as
121 explained in section 4.
122
123 Objects should only be marked as special if they are not special already.
124 If an object is to be unmarked, and a special LPC value has been set, it
125 should be reset to DGD_NIL_VALUE first.
126
127 bool DGD_OBJECT_ISSPECIAL(DGD_OBJECT_T obj); /* special object */
128 bool DGD_OBJECT_ISMARKED(DGD_OBJECT_T obj); /* user-def special */
129 void DGD_OBJECT_MARK(DGD_OBJECT_T obj); /* mark as special */
130 void DGD_OBJECT_UNMARK(DGD_OBJECT_T obj); /* unmark as special */
131
132 DGD_EINDEX_T DGD_OBJECT_GET_EINDEX(DGD_OBJECT_T obj); /* get eindex value */
133 void DGD_OBJECT_SET_EINDEX(DGD_OBJECT_T obj, DGD_EINDEX_T etabi);
134
135 To retrieve or set the LPC value associated with a special object, first
136 get the object's dataspace, and then manipulate the value.
137
138 DGD_DATASPACE_T DGD_OBJECT_DATASPACE(DGD_OBJECT_T obj);
139 DGD_VALUE_T DGD_DATA_GET_VAL(DGD_DATASPACE_T data);
140 void DGD_DATA_SET_VAL(DGD_DATASPACE_T data, DGD_VALUE_T val);
141
142
143 4. Callbacks
144
145 Callbacks can be set with the following function:
146
147 void DGD_EXT_CALLBACK(restore, swapout, destruct, funcall, cleanup,
148 finish);
149
150 The arguments are pointers to C functions, which may be NULL if no function is
151 to be called. Each function pointer is explained below.
152
153 void restore(DGD_OBJECT_T obj);
154
155 This function is called when a user-defined special object is restored from a
156 state dump file. At this point, the DGD_EINDEX_T value is no longer valid,
157 but the associated LPC value is.
158
159 void swapout(DGD_OBJECT_T obj);
160
161 This function is called when a user-defined special object is about to be
162 swapped out (including any associated LPC value).
163
164 void destruct(DGD_OBJECT_T obj);
165
166 This function is called when a user-defined special object is about to be
167 destructed. DGD_ERROR() may be called from here to prevent destruction.
168
169 bool funcall(DGD_FRAME_T f, int nargs, DGD_VALUE_T *retval, char *name);
170
171 This function is called when the LPC function with name `name' is called,
172 and that function is defined by a user-defined special object. If you want
173 to override this LPC function with one of your own, call that function and
174 return TRUE. Otherwise, return FALSE, and the normal LPC function will be
175 called.
176
177 void cleanup(void);
178
179 This function is called at the end of each LPC thread.
180
181 void finish(void);
182
183 This function is called just before the driver is about to shut down.
184
185
186 5. Operations on LPC values
187
188 The type of an LPC value can be determined with
189
190 int DGD_TYPEOF(DGD_VALUE_T val);
191
192 The types can be:
193
194 DGD_TYPE_NIL
195 DGD_TYPE_INT
196 DGD_TYPE_FLOAT
197 DGD_TYPE_STRING
198 DGD_TYPE_OBJECT
199 DGD_TYPE_ARRAY
200 DGD_TYPE_MAPPING
201
202 Each type has its own set of macros.
203
204 DGD_NIL_VALUE /* the nil value */
205
206 DGD_INT_T DGD_INT_GETVAL(DGD_VALUE_T val);
207 void DGD_INT_PUTVAL(DGD_VALUE_T val, DGD_INT_T num);
208
209 Floats consist of a 1-bit sign, a 11-bit exponent, and a 36-bit mantissa.
210 To make a C double out of a sign, exponent and mantissa, use this expression:
211
212 ((sign) ? -1 : 1) * ldexp(mantissa, exponent - 36)
213
214 To convert in the other direction, use the following code:
215
216 sign = (Cfloatval < 0);
217 mantissa = ldexp(frexp(fabs(Cfloatval), &exponent), 37);
218 --exponent;
219
220 void DGD_FLOAT_GETVAL(DGD_VALUE_T val, DGD_FLOAT_T flt);
221 void DGD_FLOAT_PUTVAL(DGD_VALUE_T val, DGD_FLOAT_T flt);
222 void DGD_FLOAT_GET(DGD_FLOAT_T flt, int sign, int exp,
223 int64 mantissa); /* assign to sign/exp/mantissa */
224 void DGD_FLOAT_PUT(DGD_FLOAT_T flt, int sign, int exp,
225 int64 mantissa);
226
227 DGD_STRING_T DGD_STRING_GETVAL(DGD_VALUE_T val);
228 void DGD_STRING_PUTVAL(DGD_VALUE_T val, DGD_STRING_T str);
229 DGD_STRING_T DGD_STRING_NEW(char *text, int len);
230 char *DGD_STRING_TEXT(DGD_STRING_T str);
231 unsigned int DGD_STRING_LENGTH(DGD_STRING_T str);
232
233 An object retrieved from an array or mapping element may be invalid. Use
234 DGD_OBJECT_CHECKVAL() to check the validity of such an object.
235
236 DGD_OBJECT_T DGD_OBJECT_GETVAL(DGD_VALUE_T val);
237 void DGD_OBJECT_PUTVAL(DGD_VALUE_T val, DGD_OBJECT_T obj);
238 bool DGD_OBJECT_CHECKVAL(DGD_VALUE_T val, DGD_OBJECT_T obj);
239 void DGD_OBJECT_NAME(char *buffer, DGD_OBJECT_T obj);
240
241 DGD_ARRAY_T DGD_ARRAY_GETVAL(DGD_VALUE_T val);
242 void DGD_ARRAY_PUTVAL(DGD_VALUE_T val, DGD_ARRAY_T arr);
243 DGD_ARRAY_T DGD_ARRAY_NEW(DGD_DATASPACE_T data, int size);
244 DGD_VALUE_T *DGD_ARRAY_ELTS(DGD_ARRAY_T arr);
245 DGD_VALUE_T DGD_ARRAY_INDEX(DGD_ARRAY_T arr, int i);
246 void DGD_ARRAY_ASSIGN(DGD_DATASPACE_T data, DGD_ARRAY_T arr,
247 int index, DGD_VALUE_T val);
248
249 The elements of a mapping may be retrieved as a sorted array of alternate
250 index-value pairs with DGD_MAPPING_ELTS().
251
252 DGD_MAPPING_T DGD_MAPPING_GETVAL(DGD_VALUE_T val);
253 void DGD_MAPPING_PUTVAL(DGD_VALUE_T val, DGD_MAPPING_T map);
254 DGD_MAPPING_T DGD_MAPPING_NEW(DGD_DATASPACE_T data);
255 DGD_VALUE_T *DGD_MAPPING_ELTS(DGD_MAPPING_T map);
256 DGD_VALUE_T DGD_MAPPING_INDEX(DGD_MAPPING_T map, DGD_VALUE_T index);
257 void DGD_MAPPING_ASSIGN(DGD_DATASPACE_T data, DGD_MAPPING_T map,
258 DGD_VALUE_T index, DGD_VALUE_T val);
259
260
261 6. Example
262
263 The following code implements a lower_case() kfun.
264
265 # include "dgd_ext.h"
266
267 static void lower_case(DGD_FRAME_T f, int nargs, DGD_VALUE_T *retval)
268 {
269 DGD_VALUE_T val;
270 DGD_STRING_T str;
271 char *p;
272 unsigned int i;
273
274 /* fetch the argument string */
275 val = DGD_FRAME_ARG(f, nargs, 0);
276 str = DGD_STRING_GETVAL(val);
277
278 /* make a copy */
279 str = DGD_STRING_NEW(DGD_STRING_TEXT(str), DGD_STRING_LENGTH(str));
280
281 /* turn to lowercase */
282 p = DGD_STRING_TEXT(str);
283 for (i = DGD_STRING_LENGTH(str); i != 0; --i) {
284 if (*p >= 'A' && *p <= 'Z') {
285 *p += 'a' - 'A';
286 }
287 p++;
288 }
289
290 /* put result in return value */
291 DGD_RETVAL_STR(retval, str);
292 }
293
294 static char lower_case_proto[] = { DGD_TYPE_STRING, DGD_TYPE_STRING, 0 };
295 static DGD_EXTKFUN_T kf[1] = {
296 "lower_case",
297 lower_case_proto,
298 &lower_case
299 };
300
301 void extension_init(void)
302 {
303 DGD_EXT_KFUN(kf, 1);
304 }
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.