You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
482 lines
13 KiB
482 lines
13 KiB
#include "codegen.h" |
|
|
|
#define OBJECT_TAG "node" |
|
#define OBJECT_TAG_LENGHT strlen(OBJECT_TAG) |
|
#define INTERFACE_TAG "interface" |
|
#define INTERFACE_TAG_LENGHT strlen(INTERFACE_TAG) |
|
#define SIGNAL_TAG "signal" |
|
#define SIGNAL_TAG_LENGHT strlen(SIGNAL_TAG) |
|
#define METHOD_TAG "method" |
|
#define METHOD_TAG_LENGHT strlen(METHOD_TAG) |
|
#define PROPERTY_TAG "property" |
|
#define PROPERTY_TAG_LENGHT strlen(PROPERTY_TAG) |
|
#define ARG_TAG "arg" |
|
#define ARG_TAG_LENGHT strlen(ARG_TAG) |
|
#define ANNOTATION_TAG "annotation" |
|
#define ANNOTATION_TAG_LENGHT strlen(ANNOTATION_TAG) |
|
|
|
//attributes |
|
#define NAME_ATTR "name" |
|
#define TYPE_ATTR "type" |
|
#define DIRECTION_ATTR "direction" |
|
#define ACCESS_ATTR "access" |
|
#define VALUE_ATTR "value" |
|
|
|
#define ACCESS_ATTR_VALUE_WRITE "write" |
|
#define ACCESS_ATTR_VALUE_READ "read" |
|
|
|
#define DBUS_INTERFACE "org.freedesktop.DBus." |
|
|
|
static DBus_Interface *iface; |
|
static DBus_Signal *d_signal; |
|
static DBus_Method *method; |
|
static DBus_Property *property; |
|
|
|
static Eina_Bool attributes_parse(const char *content, unsigned length, Eina_Simple_XML_Attribute_Cb func, const void *data); |
|
|
|
static Eina_Bool |
|
obj_attributes_parser(void *data, const char *key, const char *value) |
|
{ |
|
DBus_Object *obj = data; |
|
|
|
if (!strcmp(key, NAME_ATTR)) |
|
obj->name = strdup(value); |
|
|
|
return EINA_TRUE; |
|
} |
|
|
|
static Eina_Bool |
|
iface_attributes_parser(void *data, const char *key, const char *value) |
|
{ |
|
if (!strcmp(key, NAME_ATTR)) |
|
iface->name = strdup(value); |
|
|
|
return EINA_TRUE; |
|
} |
|
|
|
static Eina_Bool |
|
signal_attributes_parser(void *data, const char *key, const char *value) |
|
{ |
|
if (!strcmp(key, NAME_ATTR)) |
|
d_signal->name = strdup(value); |
|
|
|
return EINA_TRUE; |
|
} |
|
|
|
static Eina_Bool |
|
arg_attributes_parser(void *data, const char *key, const char *value) |
|
{ |
|
DBus_Arg *arg = data; |
|
if (!strcmp(key, NAME_ATTR)) |
|
arg->name = strdup(value); |
|
else if (!strcmp(key, TYPE_ATTR)) |
|
arg->type = strdup(value); |
|
else if (!strcmp(key, DIRECTION_ATTR)) |
|
arg->direction = value[0]; |
|
|
|
return EINA_TRUE; |
|
} |
|
|
|
static Eina_Bool |
|
method_attributes_parser(void *data, const char *key, const char *value) |
|
{ |
|
if (!strcmp(key, NAME_ATTR)) |
|
method->name = strdup(value); |
|
|
|
return EINA_TRUE; |
|
} |
|
|
|
static Eina_Bool |
|
property_attributes_parser(void *data, const char *key, const char *value) |
|
{ |
|
if (!strcmp(key, NAME_ATTR)) |
|
property->name = strdup(value); |
|
else if (!strcmp(key, TYPE_ATTR)) |
|
{ |
|
property->type = strdup(value); |
|
if (value[1] || value[0] == 'v') |
|
property->complex = EINA_TRUE; |
|
} |
|
else if (!strcmp(key, ACCESS_ATTR)) |
|
{ |
|
if (!strcmp(value, ACCESS_ATTR_VALUE_READ)) |
|
property->access = ACCESS_READ; |
|
else if (!strcmp(value, ACCESS_ATTR_VALUE_WRITE)) |
|
property->access = ACCESS_WRITE; |
|
else |
|
property->access = (ACCESS_WRITE | ACCESS_READ); |
|
} |
|
|
|
return EINA_TRUE; |
|
} |
|
|
|
static Eina_Bool |
|
open_object(const char *content, unsigned length, Eina_Bool is_open_empty, DBus_Object **ptr_obj) |
|
{ |
|
Eina_Bool r; |
|
DBus_Object *obj = *ptr_obj; |
|
|
|
if (is_open_empty) return EINA_TRUE; |
|
|
|
if (obj) |
|
{ |
|
printf("Only one object is supported per file."); |
|
return EINA_FALSE; |
|
} |
|
obj = calloc(1, sizeof(DBus_Object)); |
|
EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE); |
|
|
|
r = attributes_parse(content, length, obj_attributes_parser, obj); |
|
if (!obj->name) obj->name = strdup("/"); |
|
|
|
obj->c_name = dbus_name_to_c(obj->name); |
|
|
|
*ptr_obj = obj; |
|
return r; |
|
} |
|
|
|
static Eina_Bool |
|
open_interface(const char *content, unsigned length, Eina_Bool is_open_empty, DBus_Object *obj) |
|
{ |
|
Eina_Bool r; |
|
char *tmp_name; |
|
|
|
iface = interface_new(obj); |
|
EINA_SAFETY_ON_NULL_RETURN_VAL(iface, EINA_FALSE); |
|
|
|
r = attributes_parse(content, length, iface_attributes_parser, NULL); |
|
if (!iface->name) |
|
{ |
|
interface_free(iface); |
|
printf("Error interface without name.\n"); |
|
return EINA_FALSE; |
|
} |
|
|
|
tmp_name = get_pieces(iface->name, '.', 2); |
|
iface->c_name = dbus_name_to_c(tmp_name); |
|
free(tmp_name); |
|
|
|
return r; |
|
} |
|
|
|
static Eina_Bool |
|
open_signal(const char *content, unsigned length, Eina_Bool is_open_empty) |
|
{ |
|
Eina_Bool r; |
|
char *tmp; |
|
int i; |
|
Eina_Strbuf *buf = eina_strbuf_new(); |
|
|
|
d_signal = signal_new(iface); |
|
EINA_SAFETY_ON_NULL_RETURN_VAL(d_signal, EINA_FALSE); |
|
|
|
r = attributes_parse(content, length, signal_attributes_parser, NULL); |
|
if (!d_signal->name) |
|
{ |
|
signal_free(d_signal); |
|
d_signal = NULL; |
|
printf("Error signal without name.\n"); |
|
return EINA_FALSE; |
|
} |
|
|
|
tmp = dbus_name_to_c(d_signal->name); |
|
d_signal->c_name = string_build("%s_%s", iface->c_name, tmp); |
|
free(tmp); |
|
d_signal->cb_name = string_build("on_%s", d_signal->c_name); |
|
d_signal->free_function = string_build("%s_data_free", d_signal->c_name); |
|
d_signal->struct_name = string_build("%s_%s_Data", iface->c_name, d_signal->name); |
|
d_signal->struct_name[0] = toupper(d_signal->struct_name[0]); |
|
for (i = 0; d_signal->struct_name[i]; i++) |
|
{ |
|
if (d_signal->struct_name[i] == '_' && d_signal->struct_name[i+1]) |
|
d_signal->struct_name[i+1] = toupper(d_signal->struct_name[i+1]); |
|
} |
|
for (i = 0; iface->c_name[i]; i++) |
|
eina_strbuf_append_char(buf, toupper(iface->c_name[i])); |
|
eina_strbuf_append_char(buf, '_'); |
|
for (i = 0; d_signal->name[i]; i++) |
|
{ |
|
if (i && isupper(d_signal->name[i]) && !isupper(d_signal->name[i-1])) |
|
eina_strbuf_append_char(buf, '_'); |
|
eina_strbuf_append_char(buf, toupper(d_signal->name[i])); |
|
} |
|
eina_strbuf_append(buf, "_EVENT"); |
|
d_signal->signal_event = strdup(eina_strbuf_string_get(buf)); |
|
eina_strbuf_free(buf); |
|
|
|
return r; |
|
} |
|
|
|
#define ANNOTATION_NO_REPLY "org.freedesktop.DBus.Method.NoReply" |
|
|
|
static Eina_Bool |
|
annotation_attributes_parser(void *data, const char *key, const char *value) |
|
{ |
|
DBus_Annotation *annotation = data; |
|
if (!strcmp(key, NAME_ATTR)) |
|
{ |
|
if (!strcmp(value, ANNOTATION_NO_REPLY)) |
|
annotation->type = NO_REPLY; |
|
} |
|
else if (!strcmp(key, VALUE_ATTR)) |
|
{ |
|
unsigned i; |
|
annotation->value = strdup(value); |
|
for (i = 0; annotation->value[i]; i++) |
|
annotation->value[i] = tolower(annotation->value[i]); |
|
} |
|
|
|
return EINA_TRUE; |
|
} |
|
|
|
static Eina_Bool |
|
open_annotation(const char *content, unsigned length) |
|
{ |
|
DBus_Annotation annotation; |
|
Eina_Bool r; |
|
|
|
annotation.type = INVALID; |
|
r = attributes_parse(content, length, annotation_attributes_parser, &annotation); |
|
|
|
if (annotation.type == NO_REPLY) |
|
{ |
|
Eina_Bool value = EINA_FALSE; |
|
if (!strcmp(annotation.value, "true")) |
|
value = EINA_TRUE; |
|
free(annotation.value); |
|
|
|
if (method) |
|
method->no_reply = value; |
|
} |
|
|
|
return r; |
|
} |
|
|
|
static Eina_Bool |
|
open_arg(const char *content, unsigned length) |
|
{ |
|
Eina_Bool r; |
|
unsigned int *without_name; |
|
DBus_Arg *arg = calloc(1, sizeof(DBus_Arg)); |
|
EINA_SAFETY_ON_NULL_RETURN_VAL(arg, EINA_FALSE); |
|
|
|
r = attributes_parse(content, length, arg_attributes_parser, arg); |
|
if (d_signal) |
|
{ |
|
d_signal->args = eina_inlist_append(d_signal->args, EINA_INLIST_GET(arg)); |
|
without_name = &d_signal->arg_without_name; |
|
} |
|
else if (method) |
|
{ |
|
method->args = eina_inlist_append(method->args, EINA_INLIST_GET(arg)); |
|
without_name = &method->arg_without_name; |
|
} |
|
else |
|
{ |
|
printf("Error find an argument without any valid parent.\n"); |
|
return EINA_FALSE; |
|
} |
|
|
|
if (!arg->name) |
|
{ |
|
arg->c_name = string_build("arg%d", *without_name); |
|
(*without_name)++; |
|
} |
|
else |
|
arg->c_name = dbus_name_to_c(arg->name); |
|
|
|
return r; |
|
} |
|
|
|
static Eina_Bool |
|
open_method(const char *content, unsigned lenght) |
|
{ |
|
Eina_Bool r; |
|
char *tmp; |
|
int i; |
|
|
|
method = method_new(iface); |
|
EINA_SAFETY_ON_NULL_RETURN_VAL(method, EINA_FALSE); |
|
|
|
r = attributes_parse(content, lenght, method_attributes_parser, NULL); |
|
if (!method->name) |
|
{ |
|
method_free(method); |
|
method = NULL; |
|
printf("Error method without name.\n"); |
|
return EINA_FALSE; |
|
} |
|
|
|
tmp = dbus_name_to_c(method->name); |
|
method->c_name = string_build("%s_%s", iface->c_name, tmp); |
|
free(tmp); |
|
method->cb_name = string_build("cb_%s", method->c_name); |
|
method->function_cb = string_build("%s_Cb", method->c_name); |
|
method->function_cb[0] = toupper(method->function_cb[0]); |
|
for (i = 0; method->function_cb[i]; i++) |
|
{ |
|
if (method->function_cb[i] == '_' && method->function_cb[i+1]) |
|
method->function_cb[i+1] = toupper(method->function_cb[i+1]); |
|
} |
|
|
|
return r; |
|
} |
|
|
|
static Eina_Bool |
|
open_property(const char *content, unsigned length, Eina_Bool is_open_empty) |
|
{ |
|
Eina_Bool r; |
|
char *tmp; |
|
|
|
property = property_new(iface); |
|
EINA_SAFETY_ON_NULL_RETURN_VAL(property, EINA_FALSE); |
|
|
|
r = attributes_parse(content, length, property_attributes_parser, NULL); |
|
if (!property->name) |
|
{ |
|
property_free(property); |
|
property = NULL; |
|
printf("Error property without name.\n"); |
|
return EINA_FALSE; |
|
} |
|
|
|
tmp = dbus_name_to_c(property->name); |
|
property->c_name = string_build("%s_%s", iface->c_name, tmp); |
|
free(tmp); |
|
property->cb_name = string_build("cb_%s", property->c_name); |
|
|
|
return r; |
|
} |
|
|
|
static Eina_Bool |
|
open_tag(const char *content, unsigned length, Eina_Bool is_open_empty, DBus_Object **obj) |
|
{ |
|
unsigned int i; |
|
if (!strncmp(content, OBJECT_TAG, OBJECT_TAG_LENGHT)) |
|
return open_object(content, length, is_open_empty, obj); |
|
else if (!strncmp(content, INTERFACE_TAG, INTERFACE_TAG_LENGHT) && *obj) |
|
return open_interface(content, length, is_open_empty, *obj); |
|
else if (!strncmp(content, SIGNAL_TAG, SIGNAL_TAG_LENGHT) && iface) |
|
return open_signal(content, length, is_open_empty); |
|
else if (!strncmp(content, ARG_TAG, ARG_TAG_LENGHT) && iface) |
|
return open_arg(content, length); |
|
else if (!strncmp(content, ANNOTATION_TAG, ANNOTATION_TAG_LENGHT) && iface) |
|
return open_annotation(content, length); |
|
else if (!strncmp(content, METHOD_TAG, METHOD_TAG_LENGHT) && iface) |
|
return open_method(content, length); |
|
else if (!strncmp(content, PROPERTY_TAG, PROPERTY_TAG_LENGHT) && iface) |
|
return open_property(content, length, is_open_empty); |
|
else if (!strncmp(content, ANNOTATION_TAG, ANNOTATION_TAG_LENGHT) && iface) |
|
return EINA_TRUE; |
|
|
|
printf("Warning: Tag not handled:\n"); |
|
for (i = 0; i < length; i++) |
|
printf("%c", content[i]); |
|
printf("\n\n"); |
|
|
|
return EINA_TRUE; |
|
} |
|
|
|
static void |
|
interface_close(void) |
|
{ |
|
//its not necessary generate code to FreeDesktop interfaces |
|
if (!strncmp(iface->name, DBUS_INTERFACE, strlen(DBUS_INTERFACE))) |
|
interface_free(iface); |
|
iface = NULL; |
|
} |
|
|
|
static void |
|
signal_close(void) |
|
{ |
|
DBus_Arg *arg; |
|
EINA_INLIST_FOREACH(d_signal->args, arg) |
|
{ |
|
if ((arg->type[1]) || (arg->type[0] == 'v')) |
|
{ |
|
d_signal->complex = EINA_TRUE; |
|
break; |
|
} |
|
} |
|
d_signal = NULL; |
|
} |
|
|
|
static void |
|
method_close(void) |
|
{ |
|
DBus_Arg *arg; |
|
EINA_INLIST_FOREACH(method->args, arg) |
|
{ |
|
if ((arg->type[1]) || (arg->type[0] == 'v')) |
|
{ |
|
if (arg->direction == 'o') |
|
method->out_complex = EINA_TRUE; |
|
else |
|
method->in_complex = EINA_TRUE; |
|
} |
|
} |
|
if (method->no_reply) |
|
{ |
|
free(method->cb_name); |
|
method->cb_name = strdup("NULL"); |
|
} |
|
method = NULL; |
|
} |
|
|
|
static Eina_Bool |
|
close_tag(const char *content, unsigned length) |
|
{ |
|
if (!strncmp(content, INTERFACE_TAG, INTERFACE_TAG_LENGHT)) |
|
interface_close(); |
|
if (!strncmp(content, SIGNAL_TAG, SIGNAL_TAG_LENGHT)) |
|
signal_close(); |
|
else if (!strncmp(content, METHOD_TAG, METHOD_TAG_LENGHT)) |
|
method_close(); |
|
else if (!strncmp(content, PROPERTY_TAG, PROPERTY_TAG_LENGHT)) |
|
property = NULL; |
|
|
|
return EINA_TRUE; |
|
} |
|
|
|
Eina_Bool |
|
parser(void *data, Eina_Simple_XML_Type type, const char *content, unsigned offset, unsigned length) |
|
{ |
|
Eina_Bool r = EINA_TRUE; |
|
DBus_Object **obj = data; |
|
|
|
switch (type) |
|
{ |
|
case EINA_SIMPLE_XML_OPEN: |
|
case EINA_SIMPLE_XML_OPEN_EMPTY: |
|
{ |
|
r = open_tag(content, length, type == EINA_SIMPLE_XML_OPEN_EMPTY, |
|
obj); |
|
break; |
|
} |
|
case EINA_SIMPLE_XML_CLOSE: |
|
{ |
|
r = close_tag(content, length); |
|
break; |
|
} |
|
default: |
|
break; |
|
} |
|
return r; |
|
} |
|
|
|
static Eina_Bool |
|
attributes_parse(const char *content, unsigned length, Eina_Simple_XML_Attribute_Cb func, const void *data) |
|
{ |
|
const char *attrs = eina_simple_xml_tag_attributes_find(content, length); |
|
unsigned attrslen = 0; |
|
if (attrs) |
|
{ |
|
attrslen = length - (attrs - content); |
|
if (!eina_simple_xml_attributes_parse(attrs, attrslen, func, data)) |
|
{ |
|
printf("Parser error - attrs=%s | content=%s\n", attrs, content); |
|
return EINA_FALSE; |
|
} |
|
} |
|
return EINA_TRUE; |
|
}
|
|
|