+
+#include "specstr.h"
+
+static size_t explain_spec(char *buf, size_t n, struct cdecl_declspec *s)
+{
+ const char *keyword = spec_string(s->type);
+
+ if (keyword[0] && s->ident)
+ return snprintf(buf, n, "%s %s", keyword, s->ident);
+ else if (s->ident)
+ return snprintf(buf, n, "%s", s->ident);
+ return snprintf(buf, n, "%s", keyword);
+}
+
+/*
+ * Render a list of declaration specifiers. Only the declaration specifiers
+ * listed in mask, which is the bitwise OR of the desired specifier kinds, are
+ * printed.
+ */
+size_t cdecl__explain_specs(char *buf, size_t n, struct cdecl_declspec *s,
+ unsigned mask)
+{
+ size_t ret = 0, rc = 0;
+
+ for (struct cdecl_declspec *c = s; c; c = c->next) {
+ switch (cdecl_spec_kind(c) & mask) {
+ case CDECL_SPEC_FUNC:
+ case CDECL_SPEC_STOR:
+ case CDECL_SPEC_QUAL:
+ case CDECL_SPEC_TYPE:
+ ret += cdecl__advance(&buf, &n, rc);
+ rc = explain_spec(buf, n, c);
+ }
+ }
+
+ return ret + rc;
+}
+
+/* Renders the storage-class and function specifiers in canonical form. */
+size_t cdecl__explain_pre_specs(char *buf, size_t n, struct cdecl_declspec *s)
+{
+ return cdecl__explain_specs(buf, n, s, CDECL_SPEC_FUNC|CDECL_SPEC_STOR);
+}
+
+/* Renders the type qualifiers and type specifiers in canonical form. */
+size_t cdecl__explain_post_specs(char *buf, size_t n, struct cdecl_declspec *s)
+{
+ return cdecl__explain_specs(buf, n, s, CDECL_SPEC_QUAL|CDECL_SPEC_TYPE);
+}