scanner: Support documentation elements
authorJesse Barnes <jesse.barnes@intel.com>
Wed, 18 Jan 2012 22:09:47 +0000 (14:09 -0800)
committerKristian Høgsberg <krh@bitplanet.net>
Wed, 18 Jan 2012 23:22:25 +0000 (18:22 -0500)
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good.  I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.

How does this look?  It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others.  Spits out enum
documentation like this:

/**
 * wl_display_error - global error values
 * @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
 * @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
 * @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
 *
 * These errors are global and can be emitted in response to any server request.
 */
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};

and structure documentation like this:

/**
 * wl_display - core global object
 * @bind: bind an object to the display
 * @sync: (none)
 *
 * The core global object. This is a special singleton object. It is used for
 * internal wayland protocol features.
 */
struct wl_display_interface {
void (*bind)(struct wl_client *client,
     struct wl_resource *resource,
     uint32_t name,
     const char *interface,
     uint32_t version,
     uint32_t id);
void (*sync)(struct wl_client *client,
     struct wl_resource *resource,
     uint32_t callback);
};

protocol/wayland.xml
src/scanner.c

index cdbbfd0..8d91187 100644 (file)
   <!-- The core global object. This is a special singleton object.
        It is used for internal wayland protocol features. -->
   <interface name="wl_display" version="1">
+    <description summary="core global object">
+      The core global object. This is a special singleton object.
+      It is used for internal wayland protocol features.
+    </description>
     <request name="bind">
+      <description summary="bind an object to the display">
+      </description>
       <arg name="name" type="uint"/>
       <arg name="interface" type="string"/>
       <arg name="version" type="uint"/>
     </event>
 
     <enum name="error">
-      <entry name="invalid_object" value="0"/>
-      <entry name="invalid_method" value="1"/>
-      <entry name="no_memory" value="2"/>
+      <description summary="global error values">
+       These errors are global and can be emitted in response to any
+       server request.
+      </description>
+      <entry name="invalid_object" value="0"
+            summary="server couldn't find object"/>
+      <entry name="invalid_method" value="1"
+            summary="method doesn't exist on the specified interface"/>
+      <entry name="no_memory" value="2"
+            summary="server is out of memory"/>
     </enum>
 
     <!-- Notify the client of global objects. These are objects that
index d0b555c..e3b4226 100644 (file)
@@ -47,6 +47,11 @@ struct protocol {
        char *copyright;
 };
 
+struct description {
+       char *summary;
+       char *text;
+};
+
 struct interface {
        char *name;
        char *uppercase_name;
@@ -55,6 +60,7 @@ struct interface {
        struct wl_list event_list;
        struct wl_list enumeration_list;
        struct wl_list link;
+       struct description *description;
 };
 
 struct message {
@@ -66,6 +72,7 @@ struct message {
        int type_index;
        int all_null;
        int destructor;
+       struct description *description;
 };
 
 enum arg_type {
@@ -90,12 +97,14 @@ struct enumeration {
        char *uppercase_name;
        struct wl_list entry_list;
        struct wl_list link;
+       struct description *description;
 };
 
 struct entry {
        char *name;
        char *uppercase_name;
        char *value;
+       char *summary;
        struct wl_list link;
 };
 
@@ -106,6 +115,7 @@ struct parse_context {
        struct interface *interface;
        struct message *message;
        struct enumeration *enumeration;
+       struct description *description;
        char character_data[8192];
        int character_data_length;
 };
@@ -124,6 +134,50 @@ uppercase_dup(const char *src)
        return u;
 }
 
+static char *
+desc_dup(char *src)
+{
+       char *u;
+       int i, j = 0, col = 0, line = 0, len;
+
+       len = strlen(src) * 2;
+       u = malloc(len); /* enough room for newlines & comments */
+       if (!u)
+               return NULL;
+
+       memset(u, 0, len);
+
+       /* Strip leading space */
+       for (i = 0; isspace(src[i]); i++)
+               ;
+
+       for (; src[i]; i++) {
+               /* Collapse multiple spaces into 1 */
+               if (isspace(src[i]) && isspace(src[i + 1]))
+                   continue;
+
+               if (isspace(src[i]))
+                       src[i] = ' ';
+
+               if (col > 72 && isspace(src[i])) {
+                       if (src[i+1]) {
+                               u[j++] = '\n';
+                               u[j++] = ' ';
+                               u[j++] = '*';
+                               u[j++] = ' ';
+                       }
+                       line++;
+                       col = 0;
+               } else {
+                       u[j++] = src[i];
+                       col++;
+               }
+       }
+       u[j++] = '\0';
+
+       return u;
+}
+
 static void
 fail(struct parse_context *ctx, const char *msg)
 {
@@ -141,7 +195,8 @@ start_element(void *data, const char *element_name, const char **atts)
        struct arg *arg;
        struct enumeration *enumeration;
        struct entry *entry;
-       const char *name, *type, *interface_name, *value;
+       struct description *description;
+       const char *name, *type, *interface_name, *value, *summary;
        int i, version;
 
        name = NULL;
@@ -149,6 +204,8 @@ start_element(void *data, const char *element_name, const char **atts)
        version = 0;
        interface_name = NULL;
        value = NULL;
+       summary = NULL;
+       description = NULL;
        for (i = 0; atts[i]; i += 2) {
                if (strcmp(atts[i], "name") == 0)
                        name = atts[i + 1];
@@ -160,6 +217,8 @@ start_element(void *data, const char *element_name, const char **atts)
                        value = atts[i + 1];
                if (strcmp(atts[i], "interface") == 0)
                        interface_name = atts[i + 1];
+               if (strcmp(atts[i], "summary") == 0)
+                       summary = atts[i + 1];
        }
 
        ctx->character_data_length = 0;
@@ -182,6 +241,7 @@ start_element(void *data, const char *element_name, const char **atts)
                interface->name = strdup(name);
                interface->uppercase_name = uppercase_dup(name);
                interface->version = version;
+               interface->description = NULL;
                wl_list_init(&interface->request_list);
                wl_list_init(&interface->event_list);
                wl_list_init(&interface->enumeration_list);
@@ -259,6 +319,7 @@ start_element(void *data, const char *element_name, const char **atts)
                enumeration = malloc(sizeof *enumeration);
                enumeration->name = strdup(name);
                enumeration->uppercase_name = uppercase_dup(name);
+               enumeration->description = NULL;
                wl_list_init(&enumeration->entry_list);
 
                wl_list_insert(ctx->interface->enumeration_list.prev,
@@ -273,8 +334,32 @@ start_element(void *data, const char *element_name, const char **atts)
                entry->name = strdup(name);
                entry->uppercase_name = uppercase_dup(name);
                entry->value = strdup(value);
+               if (summary)
+                       entry->summary = strdup(summary);
+               else
+                       entry->summary = NULL;
                wl_list_insert(ctx->enumeration->entry_list.prev,
                               &entry->link);
+       } else if (strcmp(element_name, "description") == 0) {
+               if (summary == NULL)
+                       fail(ctx, "description without summary");
+
+               description = malloc(sizeof *description);
+               if (summary)
+                       description->summary = strdup(summary);
+               else
+                       description->summary = NULL;
+
+               if (ctx->message)
+                       ctx->message->description = description;
+               else if (ctx->enumeration)
+                       ctx->enumeration->description = description;
+               else if (ctx->interface)
+                       ctx->interface->description = description;
+               else
+                       fprintf(stderr,
+                               "<description> found in unsupported element\n");
+               ctx->description = description;
        }
 }
 
@@ -287,6 +372,17 @@ end_element(void *data, const XML_Char *name)
                ctx->protocol->copyright =
                        strndup(ctx->character_data,
                                ctx->character_data_length);
+       } else if (strcmp(name, "description") == 0) {
+               char *text = strndup(ctx->character_data,
+                                    ctx->character_data_length);
+               if (text)
+                       ctx->description->text = desc_dup(text);
+               ctx->description = NULL;
+       } else if (strcmp(name, "request") == 0 ||
+                  strcmp(name, "event") == 0) {
+               ctx->message = NULL;
+       } else if (strcmp(name, "enum") == 0) {
+               ctx->enumeration = NULL;
        }
 }
 
@@ -489,10 +585,30 @@ emit_enumerations(struct interface *interface)
        struct entry *entry;
 
        wl_list_for_each(e, &interface->enumeration_list, link) {
+               struct description *desc = e->description;
+
                printf("#ifndef %s_%s_ENUM\n",
                       interface->uppercase_name, e->uppercase_name);
                printf("#define %s_%s_ENUM\n",
                       interface->uppercase_name, e->uppercase_name);
+
+               if (desc) {
+                       printf("/**\n"
+                              " * %s_%s - %s\n", interface->name,
+                              e->name, desc->summary);
+                       wl_list_for_each(entry, &e->entry_list, link) {
+                               printf(" * @%s_%s_%s: %s\n",
+                                      interface->uppercase_name,
+                                      e->uppercase_name,
+                                      entry->uppercase_name,
+                                      entry->summary);
+                       }
+                       if (desc->text) {
+                               printf(" *\n"
+                                      " * %s\n", desc->text);
+                       }
+                       printf(" */\n");
+               }
                printf("enum %s_%s {\n", interface->name, e->name);
                wl_list_for_each(entry, &e->entry_list, link)
                        printf("\t%s_%s_%s = %s,\n",
@@ -516,6 +632,19 @@ emit_structs(struct wl_list *message_list, struct interface *interface)
                return;
 
        is_interface = message_list == &interface->request_list;
+       if (interface->description) {
+               struct description *desc = interface->description;
+               printf("/**\n"
+                      " * %s - %s\n", interface->name, desc->summary);
+               wl_list_for_each(m, message_list, link) {
+                       struct description *mdesc = m->description;
+                       printf(" * @%s: %s\n", m->name, mdesc ? mdesc->summary :
+                              "(none)");
+               }
+               printf(" *\n"
+                      " * %s\n"
+                      " */\n", desc->text);
+       }
        printf("struct %s_%s {\n", interface->name,
               is_interface ? "interface" : "listener");