--- /dev/null
+#include <stdio.h>
+#include <assert.h>
+
+#include "cdecl.h"
+#include "output.h"
+
+static size_t declare_specs(char *buf, size_t n, struct cdecl_declspec *s)
+{
+ size_t ret = 0, rc;
+
+ if (!s)
+ return 0;
+
+ rc = cdecl__explain_pre_specs(buf, n, s);
+ ret += cdecl__advance(&buf, &n, rc);
+
+ rc = cdecl__explain_post_specs(buf, n, s);
+ return ret + rc;
+}
+
+static size_t
+declare_declarator(char *buf, size_t n, struct cdecl_declarator *d);
+
+static size_t declare_decl(char *buf, size_t n, struct cdecl *decl)
+{
+ size_t ret = 0, rc;
+
+ rc = declare_specs(buf, n, decl->specifiers);
+ if (decl->declarators->type != CDECL_DECL_NULL)
+ ret += cdecl__advance(&buf, &n, rc);
+ else
+ ret += cdecl__advance_(&buf, &n, rc);
+
+ return ret + declare_declarator(buf, n, decl->declarators);
+}
+
+static size_t
+declare_postfix_child(char *buf, size_t n, struct cdecl_declarator *d)
+{
+ size_t ret = 0, rc;
+
+ if (d->type == CDECL_DECL_POINTER) {
+ rc = snprintf(buf, n, "(");
+ ret += cdecl__advance_(&buf, &n, rc);
+ }
+
+ rc = declare_declarator(buf, n, d);
+ ret += cdecl__advance_(&buf, &n, rc);
+
+ if (d->type == CDECL_DECL_POINTER) {
+ rc = snprintf(buf, n, ")");
+ ret += cdecl__advance_(&buf, &n, rc);
+ }
+
+ return ret;
+}
+
+static size_t declare_pointer(char *buf, size_t n, struct cdecl_pointer *p)
+{
+ size_t ret = 0, rc;
+
+ rc = snprintf(buf, n, "*");
+ if (p->qualifiers)
+ ret += cdecl__advance(&buf, &n, rc);
+ else
+ ret += cdecl__advance_(&buf, &n, rc);
+
+ rc = cdecl__explain_qualifiers(buf, n, p->qualifiers);
+ return ret + cdecl__advance(&buf, &n, rc);
+}
+
+static size_t declare_array(char *buf, size_t n, struct cdecl_array *a)
+{
+ size_t ret = 0, rc;
+
+ rc = snprintf(buf, n, "[");
+ ret += cdecl__advance_(&buf, &n, rc);
+
+ if (a->vla)
+ rc = snprintf(buf, n, "%s", a->vla[0] ? a->vla : "*");
+ else
+ rc = snprintf(buf, n, "%.0ju", a->length);
+ ret += cdecl__advance_(&buf, &n, rc);
+
+ return ret + snprintf(buf, n, "]");
+}
+
+static size_t declare_function(char *buf, size_t n, struct cdecl_function *f)
+{
+ size_t ret = 0, rc;
+
+ rc = snprintf(buf, n, "(");
+ ret += cdecl__advance_(&buf, &n, rc);
+
+ for (struct cdecl *p = f->parameters; p; p = p->next) {
+ rc = declare_decl(buf, n, p);
+ ret += cdecl__advance_(&buf, &n, rc);
+
+ if (p->next)
+ rc = snprintf(buf, n, ", ");
+ else if (f->variadic)
+ rc = snprintf(buf, n, ", ...)");
+ else
+ rc = snprintf(buf, n, ")");
+ ret += cdecl__advance_(&buf, &n, rc);
+ }
+
+ return ret;
+}
+
+static size_t
+declare_declarator(char *buf, size_t n, struct cdecl_declarator *d)
+{
+ size_t ret = 0, rc;
+
+ for (; d; d = d->child) {
+ switch (d->type) {
+ case CDECL_DECL_NULL:
+ break;
+ case CDECL_DECL_IDENT:
+ rc = snprintf(buf, n, "%s", d->u.ident);
+ ret += cdecl__advance_(&buf, &n, rc);
+ break;
+ case CDECL_DECL_POINTER:
+ rc = declare_pointer(buf, n, &d->u.pointer);
+ ret += cdecl__advance_(&buf, &n, rc);
+ break;
+ /*
+ * Arrays and functions are special: since they are postfix,
+ * we need to render the children before rendering their
+ * "bodies".
+ */
+ case CDECL_DECL_ARRAY:
+ rc = declare_postfix_child(buf, n, d->child);
+ ret += cdecl__advance_(&buf, &n, rc);
+ return ret + declare_array(buf, n, &d->u.array);
+ case CDECL_DECL_FUNCTION:
+ rc = declare_postfix_child(buf, n, d->child);
+ ret += cdecl__advance_(&buf, &n, rc);
+ return ret + declare_function(buf, n, &d->u.function);
+ default:
+ assert(0);
+ }
+ }
+
+ return ret;
+}
+
+size_t cdecl_declare(char *buf, size_t n, struct cdecl *decl)
+{
+ return declare_decl(buf, n, decl);
+}