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