#include <config.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
#include <inttypes.h>
-#include <stdbool.h>
#include <assert.h>
#include "cdecl.h"
#include "cdecl-internal.h"
-static size_t explain_pre_specs(char *buf, size_t n, struct cdecl_declspec *s)
+#define PRE_SPECS (CDECL_SPEC_FUNC|CDECL_SPEC_STOR)
+#define POST_SPECS (CDECL_SPEC_QUAL|CDECL_SPEC_TYPE)
+
+static size_t explain_specs(char **dst, size_t *dstlen, struct cdecl_declspec *s, unsigned mask)
{
- return cdecl__explain_specs(buf, n, s, CDECL_SPEC_FUNC|CDECL_SPEC_STOR);
+ size_t rc;
+
+ rc = cdecl__explain_specs(*dst, *dstlen, s, mask);
+ return cdecl__advance(dst, dstlen, rc);
}
-static size_t explain_post_specs(char *buf, size_t n, struct cdecl_declspec *s)
+static size_t
+explain_specs_post(char **dst, size_t *dstlen, struct cdecl_declspec *s)
{
- return cdecl__explain_specs(buf, n, s, CDECL_SPEC_QUAL|CDECL_SPEC_TYPE);
+ size_t rc;
+
+ rc = cdecl__explain_specs(*dst, *dstlen, s, POST_SPECS);
+ return cdecl__advance_(dst, dstlen, rc);
}
+/*
+ * If declarator declares an identifier foo, then emit "foo as "; otherwise
+ * emit nothing.
+ */
static size_t
-explain_name(char *buf, size_t n, struct cdecl_declarator *d)
+explain_name(char **dst, size_t *dstlen, struct cdecl_declarator *d)
{
+ size_t ret;
+
while (d->child)
d = d->child;
if (d->type != CDECL_DECL_IDENT)
return 0;
- return snprintf(buf, n, "%s as", d->u.ident);
+ ret = cdecl__emit(dst, dstlen, d->u.ident);
+ return ret + cdecl__emit(dst, dstlen, " as ");
}
+/*
+ * For a pointer declarator, emit "[QUAL ]pointer to ", where
+ * QUAL is the (possibly empty) list of qualifiers.
+ */
static size_t
-explain_pointer(char *buf, size_t n, struct cdecl_pointer *p)
+explain_pointer(char **dst, size_t *dstlen, struct cdecl_pointer *p)
{
- size_t ret = 0, rc;
-
- rc = cdecl__explain_specs(buf, n, p->qualifiers, CDECL_SPEC_QUAL);
- ret += cdecl__advance(&buf, &n, rc);
+ size_t ret;
- return ret + snprintf(buf, n, "pointer to");
+ ret = explain_specs(dst, dstlen, p->qualifiers, -1);
+ return ret + cdecl__emit(dst, dstlen, "pointer to ");
}
+/*
+ * For an array declarator, emit "[variable-length ]array [X ]of ", where
+ * for a variable-length array X is the (possibly omitted) identifier name,
+ * and for normal arrays X is the (possibly omitted) length.
+ */
static size_t
-explain_array(char *buf, size_t n, struct cdecl_array *a)
+explain_array(char **dst, size_t *dstlen, struct cdecl_array *a)
{
size_t ret = 0, rc = 0;
if (a->vla)
- rc = snprintf(buf, n, "variable-length array");
- else
- rc = snprintf(buf, n, "array");
- ret += cdecl__advance(&buf, &n, rc);
+ ret += cdecl__emit(dst, dstlen, "variable-length ");
+ ret += cdecl__emit(dst, dstlen, "array ");
if (a->vla) {
- rc = snprintf(buf, n, "%s", a->vla);
- ret += cdecl__advance(&buf, &n, rc);
- } else if (a->length) {
- rc = snprintf(buf, n, "%" PRIuMAX, a->length);
- ret += cdecl__advance(&buf, &n, rc);
+ rc = cdecl__emit(dst, dstlen, a->vla);
+ ret += rc;
+ } else {
+ rc = snprintf(*dst, *dstlen, "%.0" PRIuMAX, a->length);
+ ret += cdecl__advance_(dst, dstlen, rc);
}
- return ret + snprintf(buf, n, "of");
+ return ret + cdecl__emit(dst, dstlen, " of " + !rc);
}
static size_t
-explain_declarators(char *buf, size_t n, struct cdecl_declarator *decl);
+explain_declarators(char **dst, size_t *dstlen, struct cdecl_declarator *decl);
-static size_t explain_decl(char *buf, size_t n, struct cdecl *decl)
+static size_t explain_decl(char **dst, size_t *dstlen, struct cdecl *decl)
{
- size_t ret = 0, rc;
-
- rc = explain_name(buf, n, decl->declarators);
- ret += cdecl__advance(&buf, &n, rc);
-
- rc = explain_pre_specs(buf, n, decl->specifiers);
- ret += cdecl__advance(&buf, &n, rc);
+ size_t ret;
- rc = explain_declarators(buf, n, decl->declarators);
- ret += cdecl__advance(&buf, &n, rc);
+ ret = explain_name(dst, dstlen, decl->declarators);
+ ret += explain_specs(dst, dstlen, decl->specifiers, PRE_SPECS);
+ ret += explain_declarators(dst, dstlen, decl->declarators);
+ ret += explain_specs_post(dst, dstlen, decl->specifiers);
- return ret + explain_post_specs(buf, n, decl->specifiers);
+ return ret;
}
-static size_t explain_function(char *buf, size_t n, struct cdecl_function *f)
+/*
+ * For a function declarator, emit "function [PARAM ]returning ", where
+ * PARAM is the (omitted in the case of an empty non-prototype identifier
+ * list) parameter or identifier lists enclosed in parentheses.
+ */
+static size_t
+explain_function(char **dst, size_t *dstlen, struct cdecl_function *f)
{
- size_t ret = 0, rc = 0;
+ size_t ret = 0;
- rc = snprintf(buf, n, "function");
- ret += cdecl__advance(&buf, &n, rc);
+ ret += cdecl__emit(dst, dstlen, "function ");
if (f->parameters) {
- rc = snprintf(buf, n, "(");
- ret += cdecl__advance_(&buf, &n, rc);
+ struct cdecl *p;
- for (struct cdecl *p = f->parameters; p; p = p->next) {
- rc = explain_decl(buf, n, p);
- ret += cdecl__advance_(&buf, &n, rc);
+ ret += cdecl__emit(dst, dstlen, "(");
+ for (p = f->parameters; p; p = p->next) {
+ ret += explain_decl(dst, dstlen, p);
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);
+ ret += cdecl__emit(dst, dstlen, ", ");
}
+
+ if (f->variadic)
+ ret += cdecl__emit(dst, dstlen, ", ...) ");
+ else
+ ret += cdecl__emit(dst, dstlen, ") ");
}
- return ret + snprintf(buf, n, "returning");
+ return ret + cdecl__emit(dst, dstlen, "returning ");
}
static size_t
-explain_declarators(char *buf, size_t n, struct cdecl_declarator *d)
+explain_declarators(char **dst, size_t *dstlen, struct cdecl_declarator *d)
{
- size_t ret = 0, rc;
+ size_t ret;
if (d->type == CDECL_DECL_IDENT || d->type == CDECL_DECL_NULL)
return 0;
- rc = explain_declarators(buf, n, d->child);
- ret += cdecl__advance(&buf, &n, rc);
+ ret = explain_declarators(dst, dstlen, d->child);
switch (d->type) {
case CDECL_DECL_POINTER:
- return ret + explain_pointer(buf, n, &d->u.pointer);
+ return ret + explain_pointer(dst, dstlen, &d->u.pointer);
case CDECL_DECL_ARRAY:
- return ret + explain_array(buf, n, &d->u.array);
+ return ret + explain_array(dst, dstlen, &d->u.array);
case CDECL_DECL_FUNCTION:
- return ret + explain_function(buf, n, &d->u.function);
+ return ret + explain_function(dst, dstlen, &d->u.function);
default:
assert(0);
}
size_t cdecl_explain(char *buf, size_t n, struct cdecl *decl)
{
- size_t ret, rc;
+ size_t ret;
if (cdecl_is_abstract(decl->declarators))
- rc = snprintf(buf, n, "type");
+ ret = cdecl__emit(&buf, &n, "type ");
else
- rc = snprintf(buf, n, "declare");
- ret = cdecl__advance(&buf, &n, rc);
+ ret = cdecl__emit(&buf, &n, "declare ");
- return ret + explain_decl(buf, n, decl);
+ return ret + explain_decl(&buf, &n, decl);
}