The explain, simplify and declare (or type) commands are all virtually
identical. The primary difference is just which parser mode to use,
and which output mode to use, with the various combinations giving
the various commands.
Other than some very slight tweak to the formatting to handle "simplify"
with multiple full declarators, we can just implement one function that
does all three operations: a pretty nice cleanup.
#include <gettext.h>
#define _(x) gettext(x)
#include <gettext.h>
#define _(x) gettext(x)
+enum { INPUT_C, INPUT_ENGLISH };
+enum { OUTPUT_C, OUTPUT_ENGLISH };
+
int run_command(const char *line, int batch);
int run_command(const char *line, int batch);
-int run_command_simplify(const char *arg);
-int run_command_explain(const char *arg);
-int run_command_declare(const char *cmdarg);
+int run_command_cdecl(const char *s, int input_mode, int output_mode);
void print_error(const char *fmt, ...);
void print_error(const char *fmt, ...);
#include "cdecl99.h"
#include "cdecl.h"
#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
/*
* 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.
*/
*
* 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;
{
static size_t bufsz;
static char *buf;
- 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;
if (rc >= bufsz) {
char *tmp;
-int run_command_explain(const char *arg)
-{
- 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)
- struct cdecl *decl;
- const char *str;
+ struct cdecl *i, *parse;
- decl = cdecl_parse_decl(arg);
- if (!decl) {
- print_error("%s", cdecl_get_error()->str);
+ if (!(parse = do_parse(s, input_mode)))
- }
-
- 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;
+ int no_nl = 0;
+ if (!(str = do_render(i, output_mode)))
- 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;
+ /*
+ * 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;
+ no_nl = 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;
+ printf(", %s%s" + 2*!!i->specifiers, str, "\n" + no_nl);
- /*
- * 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);
- case cmd_help: return run_cmd_help();
- case cmd_declare: case cmd_type: return run_command_declare(cmd);
- case cmd_simplify: return run_command_simplify(arg);
- case cmd_explain: return run_command_explain(arg);
- case cmd_quit: return 1;
+ case cmd_help:
+ return run_cmd_help();
+ case cmd_declare: case cmd_type:
+ return run_command_cdecl(cmd, INPUT_ENGLISH, OUTPUT_C);
+ case cmd_simplify:
+ return run_command_cdecl(arg, INPUT_C, OUTPUT_C);
+ case cmd_explain:
+ return run_command_cdecl(arg, INPUT_C, OUTPUT_ENGLISH);
+ case cmd_quit:
+ return 1;