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