X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/blobdiff_plain/4ce4dd35946ea92c7f50aaaf4cc370ef6042eaf0..HEAD:/src/commands.c diff --git a/src/commands.c b/src/commands.c index fd2a5a3..a80fe76 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1,6 +1,6 @@ /* * Main command implementation routines for cdecl99. - * Copyright © 2011-2012, 2020-2021, 2023 Nick Bowler + * 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 @@ -23,6 +23,21 @@ #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 @@ -30,16 +45,18 @@ * * Returns NULL on failure. */ -static const char * -do_format(size_t func(char *, size_t, struct cdecl *), struct cdecl *decl) +static const char *do_render(struct cdecl *decl, int output_mode) { static size_t bufsz; static char *buf; - size_t rc; retry: - rc = func(buf, bufsz, decl); + if (output_mode == OUTPUT_C) + rc = cdecl_declare(buf, bufsz, decl); + else + rc = cdecl_explain(buf, bufsz, decl); + if (rc >= bufsz) { char *tmp; @@ -57,95 +74,38 @@ retry: return buf; } -int run_command_explain(const char *arg) -{ - const struct cdecl_error *err; - struct cdecl *decl; - const char *str; - int ret = -1; - - decl = cdecl_parse_decl(arg); - if (!decl) { - print_error("%s", cdecl_get_error()->str); - goto out; - } - - for (struct cdecl *i = decl; i; i = i->next) { - str = do_format(cdecl_explain, i); - if (!str) - goto out; - - printf("%s\n", str); - } - - ret = 0; -out: - cdecl_free(decl); - return ret; -} - -int run_command_simplify(const char *arg) +/* + * 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) { - const struct cdecl_error *err; - struct cdecl *decl; - const char *str; + struct cdecl *i, *parse; int ret = -1; - decl = cdecl_parse_decl(arg); - if (!decl) { - print_error("%s", cdecl_get_error()->str); + if (!(parse = do_parse(s, input_mode))) goto out; - } - - for (struct cdecl *i = decl; i; i = i->next) { - struct cdecl_declspec *s = i->specifiers; - if (i != decl) { - i->specifiers = NULL; - printf(", "); - } - - str = do_format(cdecl_declare, i); - i->specifiers = s; + for (i = parse; i; i = i->next) { + const char *str; - if (!str) + if (!(str = do_render(i, output_mode))) goto out; - printf("%s", str); - } - - putchar('\n'); - - ret = 0; -out: - cdecl_free(decl); - return ret; -} - -int run_command_declare(const char *cmd) -{ - struct cdecl *decl; - const char *str; - int ret = -1; - - /* The name of the command is significant here. */ - decl = cdecl_parse_english(cmd); - if (!decl) { - print_error("%s", cdecl_get_error()->str); - 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); + } } - /* - * English parses have at most one full declarator, so no loop is - * needed here. - */ - str = do_format(cdecl_declare, decl); - if (!str) - goto out; - - printf("%s\n", str); ret = 0; out: - cdecl_free(decl); + cdecl_free(parse); return ret; }