#include <config.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <string.h>
#include <getopt.h>
#include "readline.h"
#include "cdecl.h"
static const char *progname = "cdecl99";
-static const char sopts[] = "VH";
+static const char sopts[] = "qbiVH";
static const struct option lopts[] = {
- { "version", 0, NULL, 'V' },
- { "help", 0, NULL, 'H' },
+ { "quiet", 0, NULL, 'q' },
+ { "batch", 0, NULL, 'b' },
+ { "interactive", 0, NULL, 'i' },
+ { "version", 0, NULL, 'V' },
+ { "help", 0, NULL, 'H' },
{ 0 }
};
puts("Detailed help coming soon.");
}
-static int cmd_explain(char *cmd, char *arg)
+/*
+ * 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_format(size_t func(char *, size_t, struct cdecl *), struct cdecl *decl)
{
static size_t bufsz;
static char *buf;
- struct cdecl *decl;
size_t rc;
+retry:
+ rc = func(buf, bufsz, decl);
+ if (rc >= bufsz) {
+ char *tmp;
+
+ tmp = realloc(buf, rc + 1);
+ if (!tmp) {
+ fprintf(stderr, "failed to allocate memory\n");
+ return NULL;
+ }
+
+ buf = tmp;
+ bufsz = rc + 1;
+ goto retry;
+ }
+
+ return buf;
+}
+
+static int cmd_explain(char *cmd, char *arg)
+{
+ struct cdecl *decl;
+ const char *str;
+ int ret = -1;
+
decl = cdecl_parse_decl(arg);
if (!decl)
goto out;
for (struct cdecl *i = decl; i; i = i->next) {
-retry:
- rc = cdecl_explain(buf, bufsz, i);
- if (rc >= bufsz) {
- char *tmp;
+ str = do_format(cdecl_explain, i);
+ if (!str)
+ goto out;
- tmp = realloc(buf, rc + 1);
- if (!tmp) {
- fprintf(stderr, "failed to allocate memory\n");
- goto out;
- }
+ printf("%s\n", str);
+ }
- buf = tmp;
- bufsz = rc + 1;
- goto retry;
+ ret = 1;
+out:
+ cdecl_free(decl);
+ return ret;
+}
+
+static int cmd_simplify(char *cmd, char *arg)
+{
+ struct cdecl *decl;
+ const char *str;
+ int ret = -1;
+
+ decl = cdecl_parse_decl(arg);
+ if (!decl)
+ goto out;
+
+ for (struct cdecl *i = decl; i; i = i->next) {
+ struct cdecl_declspec *s = i->specifiers;
+
+ if (i != decl) {
+ i->specifiers = NULL;
+ printf(", ");
}
- printf("%s\n", buf);
+ str = do_format(cdecl_declare, i);
+ i->specifiers = s;
+
+ if (!str)
+ goto out;
+
+ printf("%s", str);
}
+
+ putchar('\n');
+
+ ret = 1;
out:
cdecl_free(decl);
- return 1;
+ return ret;
}
static int cmd_quit(char *cmd, char *arg)
int (*func)(char *cmd, char *arg);
const char *blurb;
} commands[] = {
- { "explain", cmd_explain, "Explain a C declaration." },
- { "help", cmd_help, "Print this list of commands." },
- { "quit", cmd_quit, "Quit the program." },
- { "exit", cmd_quit, NULL }
+ { "explain", cmd_explain, "Explain a C declaration." },
+ { "simplify", cmd_simplify, "Simplify a C declaration." },
+ { "help", cmd_help, "Print this list of commands." },
+ { "quit", cmd_quit, "Quit the program." },
+ { "exit", cmd_quit, NULL }
};
static const size_t ncommands = sizeof commands / sizeof commands[0];
return 1;
}
-static int repl(void)
+static int repl(bool interactive)
{
+ char *prompt = interactive ? "> " : NULL;
+ int rc, ret = 0;
char *line;
- int ret;
-
- print_version();
- for (; (line = readline("> ")); free(line)) {
+ for (; (line = readline(prompt)); free(line)) {
char *cmd = line + strspn(line, " \t");
char *arg = cmd + strcspn(cmd, " \t");
if (strcmp(cmd, commands[i].name) != 0)
continue;
- ret = commands[i].func(cmd, arg);
- if (ret <= 0)
+ rc = commands[i].func(cmd, arg);
+ if (!interactive && rc < 0)
+ ret = -1;
+ if (rc == 0)
goto out;
goto next;
}
fprintf(stderr, "Undefined command: %s\n", cmd);
+ ret = -1;
next:
;
}
-
- ret = 0;
out:
free(line);
return ret;
int main(int argc, char **argv)
{
+ bool show_intro = true, interactive = true;
int opt;
if (argc > 0)
while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
switch (opt) {
+ case 'q':
+ show_intro = false;
+ break;
+ case 'b':
+ interactive = false;
+ break;
+ case 'i':
+ interactive = true;
+ break;
case 'V':
print_version();
return EXIT_SUCCESS;
}
}
- if (repl() != 0)
+ if (interactive && show_intro)
+ print_version();
+
+ if (repl(interactive) != 0)
return EXIT_FAILURE;
return EXIT_SUCCESS;