/* * Render C declarations. * Copyright © 2011 Nick Bowler * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #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_specs(buf, n, p->qualifiers, CDECL_SPEC_QUAL); return ret + rc; } static bool pointer_needs_space(struct cdecl_declarator *d) { assert(d->type == CDECL_DECL_POINTER); if (d->u.pointer.qualifiers) return d->child->type != CDECL_DECL_NULL; return false; } 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); rc = 0; if (p->next) rc = snprintf(buf, n, ", "); else if (f->variadic) rc = snprintf(buf, n, ", ..."); ret += cdecl__advance_(&buf, &n, rc); } return ret + snprintf(buf, n, ")"); } 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); if (pointer_needs_space(d)) ret += cdecl__advance(&buf, &n, rc); else 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); }