/* * Render C declarations. * Copyright © 2011, 2021, 2023 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 #include "cdecl.h" #include "cdecl-internal.h" static size_t declare_declarator(char **dst, size_t *dstlen, struct cdecl_declarator *d); static size_t declare_decl(char **dst, size_t *dstlen, struct cdecl *decl) { size_t ret; ret = cdecl__emit_specs(dst, dstlen, decl->specifiers, -1); if (decl->declarators->type != CDECL_DECL_NULL) ret += cdecl__emit(dst, dstlen, " "); return ret + declare_declarator(dst, dstlen, decl->declarators); } static size_t declare_postfix_child(char **dst, size_t *dstlen, struct cdecl_declarator *d) { size_t ret = 0; if (d->type == CDECL_DECL_POINTER) ret += cdecl__emit(dst, dstlen, "("); ret += declare_declarator(dst, dstlen, d); if (d->type == CDECL_DECL_POINTER) ret += cdecl__emit(dst, dstlen, ")"); return ret; } static size_t declare_pointer(char **dst, size_t *dstlen, struct cdecl_pointer *p) { struct cdecl_declspec *q = p->qualifiers; if (q) { size_t ret; ret = cdecl__emit(dst, dstlen, "* "); ret += cdecl__emit_specs(dst, dstlen, q, -1); return ret + cdecl__emit(dst, dstlen, " "); } return cdecl__emit(dst, dstlen, "*"); } static size_t declare_array(char **dst, size_t *dstlen, struct cdecl_array *a) { size_t ret; ret = cdecl__emit(dst, dstlen, "["); if (a->vla) { const char *s = a->vla[0] ? a->vla : "*"; ret += cdecl__emit(dst, dstlen, s); } else { size_t rc = snprintf(*dst, *dstlen, "%.0" PRIuMAX, a->length); ret += cdecl__advance(dst, dstlen, rc); } return ret + cdecl__emit(dst, dstlen, "]"); } static size_t declare_function(char **dst, size_t *dstlen, struct cdecl_function *f) { struct cdecl *p; size_t ret; ret = cdecl__emit(dst, dstlen, "("); for (p = f->parameters; p; p = p->next) { ret += declare_decl(dst, dstlen, p); if (p->next) ret += cdecl__emit(dst, dstlen, ", "); else if (f->variadic) ret += cdecl__emit(dst, dstlen, ", ..."); } return ret + cdecl__emit(dst, dstlen, ")"); } static size_t declare_declarator(char **dst, size_t *dstlen, struct cdecl_declarator *d) { size_t ret = 0; for (; d; d = d->child) { switch (d->type) { case CDECL_DECL_NULL: break; case CDECL_DECL_IDENT: ret += cdecl__emit(dst, dstlen, d->u.ident); break; case CDECL_DECL_POINTER: ret += declare_pointer(dst, dstlen, &d->u.pointer); break; /* * Arrays and functions are special: since they are postfix, * we need to render the children before rendering their * "bodies". */ case CDECL_DECL_ARRAY: ret += declare_postfix_child(dst, dstlen, d->child); return ret + declare_array(dst, dstlen, &d->u.array); case CDECL_DECL_FUNCTION: ret += declare_postfix_child(dst, dstlen, d->child); return ret + declare_function(dst, dstlen, &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); }