/*
* 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;
}