/* Copyright (C) 2009 David Zeuthen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. * * Author: David Zeuthen */ #include "config.h" #include #include "dbusidl.h" static gchar **opt_input_files; static gchar *opt_output_dir; static GOptionEntry entries[] = { { "idl", 'i', 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_input_files, "IDL files (may be used several times)", NULL }, { "output", 'o', 0, G_OPTION_ARG_FILENAME, &opt_output_dir, "Directory for output", NULL }, { NULL } }; /* ---------------------------------------------------------------------------------------------------- */ static void print_type (DIType *type, GString *s, GString *sl) { GList *inner_types; GList *l; const gchar *name; name = di_type_get_name (type); if (s != NULL) g_string_append (s, name); if (sl != NULL) { g_string_append_printf (sl, "%s", name, name); } inner_types = di_type_get_inner_types (type); if (inner_types != NULL) { if (s != NULL) g_string_append (s, "<"); if (sl != NULL) g_string_append (sl, "<"); for (l = inner_types; l != NULL; l = l->next) { DIType *inner_type = l->data; print_type (inner_type, s, sl); if (l->next != NULL) { if (s != NULL) g_string_append (s, ","); if (sl != NULL) g_string_append (sl, ","); } } if (s != NULL) g_string_append (s, ">"); if (sl != NULL) g_string_append (sl, ">"); } } static guint get_type_len (DIType *type) { GString *s; guint len; s = g_string_new (NULL); print_type (type, s, NULL); len = s->len; g_string_free (s, TRUE); return len; } /* ---------------------------------------------------------------------------------------------------- */ static const gchar * get_doc (gpointer base, gboolean brief) { const gchar *doc; if (brief) doc = di_base_get_doc_brief ((DIBase *) base); else doc = di_base_get_doc ((DIBase *) base); if (doc == NULL) { if (brief) doc = "FIXME: not documented"; else doc = "FIXME: not documented."; } return doc; } /* ---------------------------------------------------------------------------------------------------- */ static void print_arg (DIArg *arg, guint arg_align, GString *s) { DIType *type; guint type_len; const gchar *prefix; switch (di_arg_get_direction (arg)) { case DI_ARG_DIRECTION_NONE: prefix = ""; break; case DI_ARG_DIRECTION_IN: prefix = "IN "; break; case DI_ARG_DIRECTION_OUT: prefix = "OUT "; break; } g_string_append (s, prefix); type = di_arg_get_type (arg); print_type (type, NULL, s); type_len = get_type_len (type); g_string_append_printf (s, "%*s%s", arg_align - type_len, "", di_arg_get_name (arg)); } static void print_method_prototype (DIMethod *method, guint align, guint arg_align, GString *s) { guint len; GList *l; guint n; len = strlen (di_method_get_name (method)); g_string_append_printf (s, "%s%*s(", di_method_get_name (method), align - len - 1, ""); for (l = di_method_get_args (method), n = 0; l != NULL; l = l->next, n++) { DIArg *arg = l->data; print_arg (arg, arg_align, s); if (l->next != NULL) g_string_append_printf (s, ",\n%*s", align, ""); } g_string_append (s, ");"); } static void print_signal_prototype (DISignal *signal, guint align, guint arg_align, GString *s) { guint len; GList *l; guint n; len = strlen (di_signal_get_name (signal)); g_string_append_printf (s, "%s%*s(", di_signal_get_name (signal), align - len - 1, ""); for (l = di_signal_get_args (signal), n = 0; l != NULL; l = l->next, n++) { DIArg *arg = l->data; print_arg (arg, arg_align, s); if (l->next != NULL) g_string_append_printf (s, ",\n%*s", align, ""); } g_string_append (s, ");"); } static void print_property_prototype (DIProperty *property, guint type_align, GString *s) { guint type_len; const gchar *modifier; switch (di_property_get_flags (property)) { case DI_PROPERTY_FLAGS_READABLE: modifier = "readonly "; break; case DI_PROPERTY_FLAGS_WRITABLE: modifier = "writeonly "; break; case DI_PROPERTY_FLAGS_READWRITE: modifier = "readwrite "; break; default: case DI_PROPERTY_FLAGS_NONE: g_assert_not_reached (); break; } g_string_append_printf (s, "%s ", modifier); type_len = get_type_len (di_property_get_type (property)); print_type (di_property_get_type (property), NULL, s); g_string_append_printf (s, "%*s%s;", type_align - type_len > 0 ? : 0, "", di_property_get_name (property)); } static guint get_arg_align_for_args (GList *args) { GList *l; guint arg_align; arg_align = 0; for (l = args; l != NULL; l = l->next) { DIArg *arg = l->data; guint arg_len; arg_len = get_type_len (di_arg_get_type (arg)); if (arg_len > arg_align) arg_align = arg_len; } return arg_align; } static void print_param (const gchar *prefix, const gchar *name, const gchar *docstring, GString *s) { g_string_append_printf (s, " \n"); g_string_append_printf (s, " %s%s :\n", prefix, name); g_string_append_printf (s, " \n"); g_string_append_printf (s, " \n"); g_string_append_printf (s, "%s\n", docstring); g_string_append_printf (s, " \n"); g_string_append_printf (s, " \n"); g_string_append_printf (s, " \n"); } static void print_args (GList *args, GString *s) { GList *l; if (args == NULL) goto out; g_string_append_printf (s, "\n"); for (l = args; l != NULL; l = l->next) { DIArg *arg = l->data; const gchar *prefix; switch (di_arg_get_direction (arg)) { case DI_ARG_DIRECTION_NONE: prefix = ""; break; case DI_ARG_DIRECTION_IN: prefix = "IN "; break; case DI_ARG_DIRECTION_OUT: prefix = "OUT "; break; } print_param (prefix, di_arg_get_name (arg), get_doc (arg, FALSE), s); } g_string_append_printf (s, "\n"); out: ; } static void print_interface (DIInterface *iface, GString *s) { GList *l; g_string_append_printf (s, "\n" " \n" " Interface %s\n" " \n" " \n" " Interface %s\n" " %s\n" " \n", di_interface_get_name (iface), di_interface_get_name (iface), di_interface_get_name (iface), get_doc (iface, TRUE)); /* Synopsis for methods */ if (di_interface_get_methods (iface) != NULL) { guint align; guint arg_align; g_string_append_printf (s, " \n"); g_string_append_printf (s, " Methods\n"); g_string_append_printf (s, " \n"); align = 0; arg_align = 0; for (l = di_interface_get_methods (iface); l != NULL; l = l->next) { DIMethod *method = l->data; guint len; guint arg_align_for_method; len = strlen (di_method_get_name (method)); if (len > align) align = len; arg_align_for_method = get_arg_align_for_args (di_method_get_args (method)); if (arg_align_for_method > arg_align) arg_align = arg_align_for_method; } for (l = di_interface_get_methods (iface); l != NULL; l = l->next) { DIMethod *method = l->data; print_method_prototype (method, align + 2, arg_align + 1, s); if (l->next != NULL) g_string_append_printf (s, "\n"); } g_string_append_printf (s, " \n"); g_string_append_printf (s, " \n"); } /* Synopsis for signals */ if (di_interface_get_signals (iface) != NULL) { guint align; guint arg_align; g_string_append_printf (s, " \n"); g_string_append_printf (s, " Signals\n"); g_string_append_printf (s, " \n"); align = 0; arg_align = 0; for (l = di_interface_get_signals (iface); l != NULL; l = l->next) { DISignal *signal = l->data; guint len; guint arg_align_for_signal; len = strlen (di_signal_get_name (signal)); if (len > align) align = len; arg_align_for_signal = get_arg_align_for_args (di_signal_get_args (signal)); if (arg_align_for_signal > arg_align) arg_align = arg_align_for_signal; } for (l = di_interface_get_signals (iface); l != NULL; l = l->next) { DISignal *signal = l->data; print_signal_prototype (signal, align + 2, arg_align + 1, s); if (l->next != NULL) g_string_append_printf (s, "\n"); } g_string_append_printf (s, " \n"); g_string_append_printf (s, " \n"); } /* Synopsis for properties */ if (di_interface_get_properties (iface) != NULL) { guint type_align; g_string_append_printf (s, " \n"); g_string_append_printf (s, " Properties\n"); g_string_append_printf (s, " \n"); type_align = 0; for (l = di_interface_get_properties (iface); l != NULL; l = l->next) { DIProperty *property = l->data; guint type_len; type_len = get_type_len (di_property_get_type (property)); if (type_len > type_align) type_align = type_len; } for (l = di_interface_get_properties (iface); l != NULL; l = l->next) { DIProperty *property = l->data; print_property_prototype (property, type_align + 1, s); if (l->next != NULL) g_string_append_printf (s, "\n"); } g_string_append_printf (s, " \n"); g_string_append_printf (s, " \n"); } /* Description */ g_string_append_printf (s, " \n"); g_string_append_printf (s, " Description\n"); g_string_append_printf (s, " \n"); g_string_append_printf (s, "%s\n", get_doc (iface, FALSE)); g_string_append_printf (s, " \n"); g_string_append_printf (s, " \n"); /* Descriptions of each method */ if (di_interface_get_methods (iface) != NULL) { g_string_append_printf (s, " \n"); g_string_append_printf (s, " Method Details\n"); for (l = di_interface_get_methods (iface); l != NULL; l = l->next) { DIMethod *method = l->data; guint arg_align_for_method; g_string_append_printf (s, " \n" " %s ()\n", di_method_get_name (method), di_method_get_name (method)); g_string_append_printf (s, " \n"); arg_align_for_method = get_arg_align_for_args (di_method_get_args (method)); print_method_prototype (method, strlen (di_method_get_name (method)) + 2, arg_align_for_method + 1, s); g_string_append_printf (s, " \n"); g_string_append_printf (s, " \n"); g_string_append_printf (s, "%s\n", get_doc (method, FALSE)); g_string_append_printf (s, " \n"); print_args (di_method_get_args (method), s); g_string_append_printf (s, " \n"); } g_string_append_printf (s, " \n"); } /* Descriptions of each signal */ if (di_interface_get_signals (iface) != NULL) { g_string_append_printf (s, " \n"); g_string_append_printf (s, " Signal Details\n"); for (l = di_interface_get_signals (iface); l != NULL; l = l->next) { DISignal *signal = l->data; guint arg_align_for_signal; g_string_append_printf (s, " \n" " %s ()\n", di_signal_get_name (signal), di_signal_get_name (signal)); g_string_append_printf (s, " \n"); arg_align_for_signal = get_arg_align_for_args (di_signal_get_args (signal)); print_signal_prototype (signal, strlen (di_signal_get_name (signal)) + 2, arg_align_for_signal + 1, s); g_string_append_printf (s, " \n"); g_string_append_printf (s, " \n"); g_string_append_printf (s, "%s\n", get_doc (signal, FALSE)); g_string_append_printf (s, " \n"); print_args (di_signal_get_args (signal), s); g_string_append_printf (s, " \n"); } g_string_append_printf (s, " \n"); } /* Descriptions of each property */ if (di_interface_get_properties (iface) != NULL) { g_string_append_printf (s, " \n"); g_string_append_printf (s, " Property Details\n"); for (l = di_interface_get_properties (iface); l != NULL; l = l->next) { DIProperty *property = l->data; g_string_append_printf (s, " \n" " %s ()\n", di_property_get_name (property), di_property_get_name (property)); g_string_append_printf (s, " \n"); print_property_prototype (property, 1, s); g_string_append_printf (s, " \n"); g_string_append_printf (s, " \n"); g_string_append_printf (s, "%s\n", get_doc (property, FALSE)); g_string_append_printf (s, " \n"); g_string_append_printf (s, " \n"); } g_string_append_printf (s, " \n"); } g_string_append_printf (s, "\n"); } /* ---------------------------------------------------------------------------------------------------- */ static void print_struct_members (GList *members, const gchar *struct_type, const gchar *struct_name, const gchar *struct_docs, GString *s) { GList *l; guint type_align; g_string_append_printf (s, " \n"); g_string_append_printf (s, " Details\n"); type_align = 0; for (l = members; l != NULL; l = l->next) { DIStructMember *member = l->data; guint type_len; type_len = get_type_len (di_struct_member_get_type (member)); if (type_len > type_align) type_align = type_len; } g_string_append_printf (s, " \n"); g_string_append_printf (s, "%s %s\n" "{\n", struct_type, struct_name); for (l = members; l != NULL; l = l->next) { DIStructMember *member = l->data; guint type_len; type_len = get_type_len (di_struct_member_get_type (member)); g_string_append_printf (s, " "); print_type (di_struct_member_get_type (member), NULL, s); g_string_append_printf (s, "%*s %s;\n", type_align - type_len, "", di_struct_member_get_name (member)); } g_string_append_printf (s, "};"); g_string_append_printf (s, " \n"); g_string_append_printf (s, " \n"); g_string_append_printf (s, "%s\n", struct_docs); g_string_append_printf (s, " \n"); g_string_append_printf (s, "\n"); for (l = members; l != NULL; l = l->next) { DIStructMember *member = l->data; print_param ("", di_struct_member_get_name (member), get_doc (member, FALSE), s); } g_string_append_printf (s, "\n"); g_string_append_printf (s, " \n"); g_string_append_printf (s, "\n"); } static void print_struct (DIStruct *struct_, GString *s) { g_string_append_printf (s, "\n" " \n" " Struct %s\n" " \n" " \n" " Struct %s\n" " %s\n" " \n", di_struct_get_name (struct_), di_struct_get_name (struct_), di_struct_get_name (struct_), get_doc (struct_, TRUE)); print_struct_members (di_struct_get_members (struct_), "struct", di_struct_get_name (struct_), get_doc (struct_, FALSE), s); } /* ---------------------------------------------------------------------------------------------------- */ static void print_enum (DIEnum *enum_, GString *s) { g_string_append_printf (s, "\n" " \n" " Enum %s\n" " \n" " \n" " Enum %s\n" " %s\n" " \n", di_enum_get_name (enum_), di_enum_get_name (enum_), di_enum_get_name (enum_), get_doc (enum_, TRUE)); GList *l; guint name_align; g_string_append_printf (s, " \n"); g_string_append_printf (s, " Details\n"); name_align = 0; for (l = di_enum_get_members (enum_); l != NULL; l = l->next) { DIEnumMember *member = l->data; guint name_len; name_len = strlen (di_enum_member_get_name (member)); if (name_len > name_align) name_align = name_len; } g_string_append_printf (s, " \n"); g_string_append_printf (s, "enum %s\n" "{\n", di_enum_get_name (enum_)); for (l = di_enum_get_members (enum_); l != NULL; l = l->next) { DIEnumMember *member = l->data; guint name_len; name_len = strlen (di_enum_member_get_name (member)); g_string_append_printf (s, " "); g_string_append_printf (s, "%s%*s = %d", di_enum_member_get_name (member), name_align - name_len, "", di_enum_member_get_value (member)); if (l->next != NULL) g_string_append_printf (s, ","); g_string_append_printf (s, "\n"); } g_string_append_printf (s, "};"); g_string_append_printf (s, " \n"); g_string_append_printf (s, " \n"); g_string_append_printf (s, "%s\n", get_doc (enum_, FALSE)); g_string_append_printf (s, " \n"); g_string_append_printf (s, "\n"); for (l = di_enum_get_members (enum_); l != NULL; l = l->next) { DIEnumMember *member = l->data; print_param ("", di_enum_member_get_name (member), get_doc (member, FALSE), s); } g_string_append_printf (s, "\n"); g_string_append_printf (s, " \n"); g_string_append_printf (s, "\n"); } /* ---------------------------------------------------------------------------------------------------- */ static void print_error_domain (DIErrorDomain *error_domain, GString *s) { g_string_append_printf (s, "\n" " \n" " Error Domain %s\n" " \n" " \n" " Error Domain %s\n" " %s\n" " \n", di_error_domain_get_name (error_domain), di_error_domain_get_name (error_domain), di_error_domain_get_name (error_domain), get_doc (error_domain, TRUE)); GList *l; g_string_append_printf (s, " \n"); g_string_append_printf (s, " Details\n"); g_string_append_printf (s, " \n"); g_string_append_printf (s, "error_domain %s\n" "{\n", di_error_domain_get_name (error_domain)); for (l = di_error_domain_get_members (error_domain); l != NULL; l = l->next) { DIErrorMember *member = l->data; g_string_append_printf (s, " %s", di_error_member_get_name (member)); if (l->next != NULL) g_string_append_printf (s, ","); g_string_append_printf (s, "\n"); } g_string_append_printf (s, "};"); g_string_append_printf (s, " \n"); g_string_append_printf (s, " \n"); g_string_append_printf (s, "%s\n", get_doc (error_domain, FALSE)); g_string_append_printf (s, " \n"); g_string_append_printf (s, "\n"); for (l = di_error_domain_get_members (error_domain); l != NULL; l = l->next) { DIErrorMember *member = l->data; print_param ("", di_error_member_get_name (member), get_doc (member, FALSE), s); } g_string_append_printf (s, "\n"); g_string_append_printf (s, " \n"); g_string_append_printf (s, "\n"); } /* ---------------------------------------------------------------------------------------------------- */ static gboolean write_file (const gchar *filename, GString *s, GError **error) { gboolean ret; gchar *path; ret = FALSE; path = NULL; if (opt_output_dir == NULL) path = g_strdup (filename); else path = g_build_filename (opt_output_dir, filename, NULL); if (!g_file_set_contents (path, s->str, s->len, error)) goto out; ret = TRUE; out: g_free (path); return ret; } static gboolean print_all (DIParser *parser, GError **error) { GList *l; gboolean ret; gchar *filename; ret = FALSE; /* ---------------------------------------------------------------------------------------------------- */ /* Print all interfaces */ for (l = di_parser_get_interfaces (parser); l != NULL; l = l->next) { DIInterface *iface = l->data; GString *s; s = g_string_new (NULL); g_string_append (s, "\n" "\n"); print_interface (iface, s); filename = g_strdup_printf ("didl-%s.xml", di_interface_get_name (iface)); if (!write_file (filename, s, error)) { g_free (filename); g_string_free (s, TRUE); goto out; } g_string_free (s, TRUE); g_free (filename); } /* ---------------------------------------------------------------------------------------------------- */ /* Print all structs */ for (l = di_parser_get_structs (parser); l != NULL; l = l->next) { DIStruct *struct_ = l->data; GString *s; s = g_string_new (NULL); g_string_append (s, "\n" "\n"); print_struct (struct_, s); filename = g_strdup_printf ("didl-%s.xml", di_struct_get_name (struct_)); if (!write_file (filename, s, error)) { g_free (filename); g_string_free (s, TRUE); goto out; } g_string_free (s, TRUE); g_free (filename); } /* ---------------------------------------------------------------------------------------------------- */ /* Print all enums */ for (l = di_parser_get_enums (parser); l != NULL; l = l->next) { DIEnum *enum_ = l->data; GString *s; s = g_string_new (NULL); g_string_append (s, "\n" "\n"); print_enum (enum_, s); filename = g_strdup_printf ("didl-%s.xml", di_enum_get_name (enum_)); if (!write_file (filename, s, error)) { g_free (filename); g_string_free (s, TRUE); goto out; } g_string_free (s, TRUE); g_free (filename); } /* ---------------------------------------------------------------------------------------------------- */ /* Print all error domains */ for (l = di_parser_get_error_domains (parser); l != NULL; l = l->next) { DIErrorDomain *error_domain = l->data; GString *s; s = g_string_new (NULL); g_string_append (s, "\n" "\n"); print_error_domain (error_domain, s); filename = g_strdup_printf ("didl-%s.xml", di_error_domain_get_name (error_domain)); if (!write_file (filename, s, error)) { g_free (filename); g_string_free (s, TRUE); goto out; } g_string_free (s, TRUE); g_free (filename); } /* ---------------------------------------------------------------------------------------------------- */ ret = TRUE; out: return ret; } /* ---------------------------------------------------------------------------------------------------- */ int main (int argc, char *argv[]) { DIParser *parser; GList *l; gint ret; gchar *s; GError *error; GOptionContext *context; opt_input_files = NULL; opt_output_dir = NULL; ret = 1; error = NULL; context = g_option_context_new ("- D-Bus IDL to Docbook compiler"); g_option_context_add_main_entries (context, entries, NULL); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("option parsing failed: %s\n", error->message); goto out; } if (opt_input_files == NULL) { s = g_option_context_get_help (context, FALSE, NULL); g_print ("%s\n", s); g_free (s); goto out; } parser = di_parser_new (opt_input_files); for (l = di_parser_get_errors (parser); l != NULL; l = l->next) { g_printerr ("%s\n", (const gchar *) l->data); } for (l = di_parser_get_warnings (parser); l != NULL; l = l->next) { g_printerr ("%s\n", (const gchar *) l->data); } if (di_parser_get_errors (parser) != NULL) goto out; error = NULL; if (!print_all (parser, &error)) { g_printerr ("Error writing file: %s", error->message); g_error_free (error); goto out; } ret = 0; out: if (parser != NULL) di_parser_free (parser); if (context != NULL) g_option_context_free (context); g_strfreev (opt_input_files); g_free (opt_output_dir); return ret;; }