1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include "codegen.h"
6
7 #define OBJECT_TAG "node"
8 #define OBJECT_TAG_LENGTH sizeof(OBJECT_TAG) - 1
9 #define INTERFACE_TAG "interface"
10 #define INTERFACE_TAG_LENGTH sizeof(INTERFACE_TAG) - 1
11 #define SIGNAL_TAG "signal"
12 #define SIGNAL_TAG_LENGTH sizeof(SIGNAL_TAG) - 1
13 #define METHOD_TAG "method"
14 #define METHOD_TAG_LENGTH sizeof(METHOD_TAG) - 1
15 #define PROPERTY_TAG "property"
16 #define PROPERTY_TAG_LENGTH sizeof(PROPERTY_TAG) - 1
17 #define ARG_TAG "arg"
18 #define ARG_TAG_LENGTH sizeof(ARG_TAG) - 1
19 #define ANNOTATION_TAG "annotation"
20 #define ANNOTATION_TAG_LENGTH sizeof(ANNOTATION_TAG) - 1
21
22 //attributes
23 #define NAME_ATTR "name"
24 #define TYPE_ATTR "type"
25 #define DIRECTION_ATTR "direction"
26 #define ACCESS_ATTR "access"
27 #define VALUE_ATTR "value"
28
29 #define ACCESS_ATTR_VALUE_WRITE "write"
30 #define ACCESS_ATTR_VALUE_READ "read"
31
32 #define DBUS_INTERFACE "org.freedesktop.DBus."
33
34 static DBus_Interface *iface;
35 static DBus_Signal *d_signal;
36 static DBus_Method *method;
37 static DBus_Property *property;
38
39 static Eina_Bool attributes_parse(const char *content, unsigned length, Eina_Simple_XML_Attribute_Cb func, const void *data);
40
41 static Eina_Bool
obj_attributes_parser(void * data,const char * key,const char * value)42 obj_attributes_parser(void *data, const char *key, const char *value)
43 {
44 DBus_Object *obj = data;
45
46 if (!strcmp(key, NAME_ATTR))
47 obj->name = strdup(value);
48
49 return EINA_TRUE;
50 }
51
52 static Eina_Bool
iface_attributes_parser(void * data EINA_UNUSED,const char * key,const char * value)53 iface_attributes_parser(void *data EINA_UNUSED, const char *key, const char *value)
54 {
55 if (!strcmp(key, NAME_ATTR))
56 iface->name = strdup(value);
57
58 return EINA_TRUE;
59 }
60
61 static Eina_Bool
signal_attributes_parser(void * data EINA_UNUSED,const char * key,const char * value)62 signal_attributes_parser(void *data EINA_UNUSED, const char *key, const char *value)
63 {
64 if (!strcmp(key, NAME_ATTR))
65 d_signal->name = strdup(value);
66
67 return EINA_TRUE;
68 }
69
70 static Eina_Bool
arg_attributes_parser(void * data EINA_UNUSED,const char * key,const char * value)71 arg_attributes_parser(void *data EINA_UNUSED, const char *key, const char *value)
72 {
73 DBus_Arg *arg = data;
74 if (!strcmp(key, NAME_ATTR))
75 arg->name = strdup(value);
76 else if (!strcmp(key, TYPE_ATTR))
77 arg->type = strdup(value);
78 else if (!strcmp(key, DIRECTION_ATTR))
79 arg->direction = value[0];
80
81 return EINA_TRUE;
82 }
83
84 static Eina_Bool
method_attributes_parser(void * data EINA_UNUSED,const char * key,const char * value)85 method_attributes_parser(void *data EINA_UNUSED, const char *key, const char *value)
86 {
87 if (!strcmp(key, NAME_ATTR))
88 method->name = strdup(value);
89
90 return EINA_TRUE;
91 }
92
93 static Eina_Bool
property_attributes_parser(void * data EINA_UNUSED,const char * key,const char * value)94 property_attributes_parser(void *data EINA_UNUSED, const char *key, const char *value)
95 {
96 if (!strcmp(key, NAME_ATTR))
97 property->name = strdup(value);
98 else if (!strcmp(key, TYPE_ATTR))
99 {
100 property->type = strdup(value);
101 if (value[1] || value[0] == 'v')
102 property->complex = EINA_TRUE;
103 }
104 else if (!strcmp(key, ACCESS_ATTR))
105 {
106 if (!strcmp(value, ACCESS_ATTR_VALUE_READ))
107 property->access = ACCESS_READ;
108 else if (!strcmp(value, ACCESS_ATTR_VALUE_WRITE))
109 property->access = ACCESS_WRITE;
110 else
111 property->access = (ACCESS_WRITE | ACCESS_READ);
112 }
113
114 return EINA_TRUE;
115 }
116
117 static Eina_Bool
open_object(const char * content,unsigned length,Eina_Bool is_open_empty,DBus_Object ** ptr_obj)118 open_object(const char *content, unsigned length, Eina_Bool is_open_empty, DBus_Object **ptr_obj)
119 {
120 Eina_Bool r;
121 DBus_Object *obj = *ptr_obj;
122
123 if (is_open_empty) return EINA_TRUE;
124
125 if (obj)
126 {
127 printf("Only one object is supported per file.");
128 return EINA_FALSE;
129 }
130 obj = calloc(1, sizeof(DBus_Object));
131 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
132
133 r = attributes_parse(content, length, obj_attributes_parser, obj);
134 if (!obj->name) obj->name = strdup("/");
135
136 obj->c_name = dbus_name_to_c(obj->name);
137
138 *ptr_obj = obj;
139 return r;
140 }
141
142 static void
interface_close(void)143 interface_close(void)
144 {
145 //its not necessary generate code to FreeDesktop interfaces
146 if (!strncmp(iface->name, DBUS_INTERFACE, strlen(DBUS_INTERFACE)))
147 {
148 printf("Refusing to generate code for FDO interface; see eldbus_freedesktop.h\n");
149 interface_free(iface);
150 }
151 iface = NULL;
152 }
153
154 static Eina_Bool
open_interface(const char * content,unsigned length,Eina_Bool is_open_empty,DBus_Object * obj)155 open_interface(const char *content, unsigned length, Eina_Bool is_open_empty, DBus_Object *obj)
156 {
157 Eina_Bool r;
158 char *tmp_name;
159
160 iface = interface_new(obj);
161 EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE);
162
163 r = attributes_parse(content, length, iface_attributes_parser, NULL);
164 if (!iface->name)
165 {
166 interface_free(iface);
167 printf("Error interface without name.\n");
168 return EINA_FALSE;
169 }
170
171 tmp_name = get_pieces(iface->name, '.', 2);
172 iface->c_name = dbus_name_to_c(tmp_name);
173 free(tmp_name);
174
175 if (is_open_empty)
176 interface_close();
177
178 return r;
179 }
180
181 static void
signal_close(void)182 signal_close(void)
183 {
184 DBus_Arg *arg;
185 EINA_INLIST_FOREACH(d_signal->args, arg)
186 {
187 if ((arg->type[1]) || (arg->type[0] == 'v'))
188 {
189 d_signal->complex = EINA_TRUE;
190 break;
191 }
192 }
193 d_signal = NULL;
194 }
195
196 static Eina_Bool
open_signal(const char * content,unsigned length,Eina_Bool is_open_empty)197 open_signal(const char *content, unsigned length, Eina_Bool is_open_empty)
198 {
199 Eina_Bool r;
200 char *tmp;
201 int i;
202 Eina_Strbuf *buf;
203
204 d_signal = signal_new(iface);
205 EINA_SAFETY_ON_NULL_RETURN_VAL(d_signal, EINA_FALSE);
206
207 r = attributes_parse(content, length, signal_attributes_parser, NULL);
208 if (!d_signal->name)
209 {
210 signal_free(d_signal);
211 d_signal = NULL;
212 printf("Error signal without name.\n");
213 return EINA_FALSE;
214 }
215
216 buf = eina_strbuf_new();
217 tmp = dbus_name_to_c(d_signal->name);
218 d_signal->c_name = string_build("%s_%s", iface->c_name, tmp);
219 free(tmp);
220 d_signal->cb_name = string_build("on_%s", d_signal->c_name);
221 d_signal->free_function = string_build("%s_data_free", d_signal->c_name);
222 d_signal->struct_name = string_build("%s_%s_Data", iface->c_name, d_signal->name);
223 d_signal->struct_name[0] = toupper(d_signal->struct_name[0]);
224 for (i = 0; d_signal->struct_name[i]; i++)
225 {
226 if (d_signal->struct_name[i] == '_' && d_signal->struct_name[i+1])
227 d_signal->struct_name[i+1] = toupper(d_signal->struct_name[i+1]);
228 }
229 for (i = 0; iface->c_name[i]; i++)
230 eina_strbuf_append_char(buf, toupper(iface->c_name[i]));
231 eina_strbuf_append_char(buf, '_');
232 for (i = 0; d_signal->name[i]; i++)
233 {
234 if (i && isupper(d_signal->name[i]) && !isupper(d_signal->name[i-1]))
235 eina_strbuf_append_char(buf, '_');
236 eina_strbuf_append_char(buf, toupper(d_signal->name[i]));
237 }
238 eina_strbuf_append(buf, "_EVENT");
239 d_signal->signal_event = eina_strbuf_string_steal(buf);
240 eina_strbuf_free(buf);
241
242 if (is_open_empty)
243 signal_close();
244
245 return r;
246 }
247
248 #define ANNOTATION_NO_REPLY "org.freedesktop.DBus.Method.NoReply"
249
250 static Eina_Bool
annotation_attributes_parser(void * data,const char * key,const char * value)251 annotation_attributes_parser(void *data, const char *key, const char *value)
252 {
253 DBus_Annotation *annotation = data;
254 if (!strcmp(key, NAME_ATTR))
255 {
256 if (!strcmp(value, ANNOTATION_NO_REPLY))
257 annotation->type = NO_REPLY;
258 }
259 else if (!strcmp(key, VALUE_ATTR))
260 {
261 unsigned i;
262 annotation->value = strdup(value);
263 for (i = 0; annotation->value[i]; i++)
264 annotation->value[i] = tolower(annotation->value[i]);
265 }
266
267 return EINA_TRUE;
268 }
269
270 static Eina_Bool
open_annotation(const char * content,unsigned length)271 open_annotation(const char *content, unsigned length)
272 {
273 DBus_Annotation annotation;
274 Eina_Bool r;
275
276 annotation.type = INVALID;
277 r = attributes_parse(content, length, annotation_attributes_parser, &annotation);
278
279 if (annotation.type == NO_REPLY)
280 {
281 Eina_Bool value = EINA_FALSE;
282 if (!strcmp(annotation.value, "true"))
283 value = EINA_TRUE;
284 free(annotation.value);
285
286 if (method)
287 method->no_reply = value;
288 }
289
290 return r;
291 }
292
293 static Eina_Bool
open_arg(const char * content,unsigned length)294 open_arg(const char *content, unsigned length)
295 {
296 Eina_Bool r;
297 unsigned int *without_name;
298 DBus_Arg *arg = calloc(1, sizeof(DBus_Arg));
299 EINA_SAFETY_ON_NULL_RETURN_VAL(arg, EINA_FALSE);
300
301 r = attributes_parse(content, length, arg_attributes_parser, arg);
302 if (d_signal)
303 {
304 d_signal->args = eina_inlist_append(d_signal->args, EINA_INLIST_GET(arg));
305 without_name = &d_signal->arg_without_name;
306 }
307 else if (method)
308 {
309 method->args = eina_inlist_append(method->args, EINA_INLIST_GET(arg));
310 without_name = &method->arg_without_name;
311 }
312 else
313 {
314 printf("Error find an argument without any valid parent.\n");
315 return EINA_FALSE;
316 }
317
318 if (!arg->name)
319 {
320 arg->c_name = string_build("arg%d", *without_name);
321 (*without_name)++;
322 }
323 else
324 arg->c_name = dbus_name_to_c(arg->name);
325
326 return r;
327 }
328
329 static void
method_close(void)330 method_close(void)
331 {
332 DBus_Arg *arg;
333 EINA_INLIST_FOREACH(method->args, arg)
334 {
335 if ((arg->type[1]) || (arg->type[0] == 'v'))
336 {
337 if (arg->direction == 'o')
338 method->out_complex = EINA_TRUE;
339 else
340 method->in_complex = EINA_TRUE;
341 }
342 }
343 if (method->no_reply)
344 {
345 free(method->cb_name);
346 method->cb_name = strdup("NULL");
347 }
348 method = NULL;
349 }
350
351 static Eina_Bool
open_method(const char * content,unsigned lenght,Eina_Bool is_open_empty)352 open_method(const char *content, unsigned lenght, Eina_Bool is_open_empty)
353 {
354 Eina_Bool r;
355 char *tmp;
356 int i;
357
358 method = method_new(iface);
359 EINA_SAFETY_ON_NULL_RETURN_VAL(method, EINA_FALSE);
360
361 r = attributes_parse(content, lenght, method_attributes_parser, NULL);
362 if (!method->name)
363 {
364 method_free(method);
365 method = NULL;
366 printf("Error method without name.\n");
367 return EINA_FALSE;
368 }
369
370 tmp = dbus_name_to_c(method->name);
371 method->c_name = string_build("%s_%s", iface->c_name, tmp);
372 free(tmp);
373 method->cb_name = string_build("cb_%s", method->c_name);
374 method->function_cb = string_build("%s_Cb", method->c_name);
375 method->function_cb[0] = toupper(method->function_cb[0]);
376 for (i = 0; method->function_cb[i]; i++)
377 {
378 if (method->function_cb[i] == '_' && method->function_cb[i+1])
379 method->function_cb[i+1] = toupper(method->function_cb[i+1]);
380 }
381
382 if (is_open_empty)
383 method_close();
384
385 return r;
386 }
387
388 static Eina_Bool
open_property(const char * content,unsigned length)389 open_property(const char *content, unsigned length)
390 {
391 Eina_Bool r;
392 char *tmp;
393
394 property = property_new(iface);
395 EINA_SAFETY_ON_NULL_RETURN_VAL(property, EINA_FALSE);
396
397 r = attributes_parse(content, length, property_attributes_parser, NULL);
398 if (!property->name)
399 {
400 property_free(property);
401 property = NULL;
402 printf("Error property without name.\n");
403 return EINA_FALSE;
404 }
405
406 tmp = dbus_name_to_c(property->name);
407 property->c_name = string_build("%s_%s", iface->c_name, tmp);
408 free(tmp);
409 property->cb_name = string_build("cb_%s", property->c_name);
410
411 return r;
412 }
413
414 static Eina_Bool
open_tag(const char * content,unsigned length,Eina_Bool is_open_empty,DBus_Object ** obj)415 open_tag(const char *content, unsigned length, Eina_Bool is_open_empty, DBus_Object **obj)
416 {
417 unsigned int i;
418 if (!strncmp(content, OBJECT_TAG, OBJECT_TAG_LENGTH))
419 return open_object(content, length, is_open_empty, obj);
420 else if (!strncmp(content, INTERFACE_TAG, INTERFACE_TAG_LENGTH) && *obj)
421 return open_interface(content, length, is_open_empty, *obj);
422 else if (!strncmp(content, SIGNAL_TAG, SIGNAL_TAG_LENGTH) && iface)
423 return open_signal(content, length, is_open_empty);
424 else if (!strncmp(content, ARG_TAG, ARG_TAG_LENGTH) && iface)
425 return open_arg(content, length);
426 else if (!strncmp(content, ANNOTATION_TAG, ANNOTATION_TAG_LENGTH) && iface)
427 return open_annotation(content, length);
428 else if (!strncmp(content, METHOD_TAG, METHOD_TAG_LENGTH) && iface)
429 return open_method(content, length, is_open_empty);
430 else if (!strncmp(content, PROPERTY_TAG, PROPERTY_TAG_LENGTH) && iface)
431 return open_property(content, length);
432
433 printf("Warning: Tag not handled:\n");
434 for (i = 0; i < length; i++)
435 printf("%c", content[i]);
436 printf("\n\n");
437
438 return EINA_TRUE;
439 }
440
441 static Eina_Bool
close_tag(const char * content)442 close_tag(const char *content)
443 {
444 if (!strncmp(content, INTERFACE_TAG, INTERFACE_TAG_LENGTH))
445 interface_close();
446 if (!strncmp(content, SIGNAL_TAG, SIGNAL_TAG_LENGTH))
447 signal_close();
448 else if (!strncmp(content, METHOD_TAG, METHOD_TAG_LENGTH))
449 method_close();
450 else if (!strncmp(content, PROPERTY_TAG, PROPERTY_TAG_LENGTH))
451 property = NULL;
452
453 return EINA_TRUE;
454 }
455
456 Eina_Bool
parser(void * data,Eina_Simple_XML_Type type,const char * content,unsigned offset EINA_UNUSED,unsigned length)457 parser(void *data, Eina_Simple_XML_Type type, const char *content, unsigned offset EINA_UNUSED, unsigned length)
458 {
459 Eina_Bool r = EINA_TRUE;
460 DBus_Object **obj = data;
461
462 switch (type)
463 {
464 case EINA_SIMPLE_XML_OPEN:
465 case EINA_SIMPLE_XML_OPEN_EMPTY:
466 {
467 r = open_tag(content, length, type == EINA_SIMPLE_XML_OPEN_EMPTY,
468 obj);
469 break;
470 }
471 case EINA_SIMPLE_XML_CLOSE:
472 {
473 r = close_tag(content);
474 break;
475 }
476 default:
477 break;
478 }
479 return r;
480 }
481
482 static Eina_Bool
attributes_parse(const char * content,unsigned length,Eina_Simple_XML_Attribute_Cb func,const void * data)483 attributes_parse(const char *content, unsigned length, Eina_Simple_XML_Attribute_Cb func, const void *data)
484 {
485 const char *attrs = eina_simple_xml_tag_attributes_find(content, length);
486 unsigned attrslen = 0;
487 if (attrs)
488 {
489 attrslen = length - (attrs - content);
490 if (!eina_simple_xml_attributes_parse(attrs, attrslen, func, data))
491 {
492 printf("Parser error - attrs=%s | content=%s\n", attrs, content);
493 return EINA_FALSE;
494 }
495 }
496 return EINA_TRUE;
497 }
498