/* * Main command implementation routines for cdecl99. * Copyright © 2011-2012, 2020-2021, 2023-2024 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 "cdecl99.h" #include "cdecl.h" static struct cdecl *do_parse(const char *s, int input_mode) { struct cdecl *parse; if (input_mode == INPUT_C) parse = cdecl_parse_decl(s); else parse = cdecl_parse_english(s); if (!parse) print_error("%s", cdecl_get_error()->str); return parse; } /* * Format a declaration according to the given function and return a pointer * to the formatted string. The returned pointer remains valid until the * next call, after which it must not be re-used. * * Returns NULL on failure. */ static const char *do_render(struct cdecl *decl, int output_mode) { static size_t bufsz; static char *buf; size_t rc; retry: if (output_mode == OUTPUT_C) rc = cdecl_declare(buf, bufsz, decl); else rc = cdecl_explain(buf, bufsz, decl); if (rc >= bufsz) { char *tmp; tmp = realloc(buf, rc + 1); if (!tmp) { print_error("%s", _("failed to allocate memory")); return NULL; } buf = tmp; bufsz = rc + 1; goto retry; } return buf; } /* * Parse the given string as either C or English (based on input_mode), * then print the result as either C or English (based on output_mode). */ int run_command_cdecl(const char *s, int input_mode, int output_mode) { struct cdecl *i, *parse; int ret = -1; if (!(parse = do_parse(s, input_mode))) goto out; for (i = parse; i; i = i->next) { const char *str; if (!(str = do_render(i, output_mode))) goto out; /* * In C output, only the first declarator needs specifiers * printed, and only the last declarator needs a newline. */ if (output_mode == OUTPUT_C && i->next) { i->next->specifiers = NULL; printf("%s, ", str); } else { puts(str); } } ret = 0; out: cdecl_free(parse); return ret; }