/* * Command line utility for making sense of C declarations. * Copyright © 2011-2012, 2020-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 #include #include #include #include #include #include #include #include #include #include #include "cdecl99.h" #include "cdecl.h" #include "help.h" #include "xtra.h" #include "options.h" #include "version.h" #include "getline.h" #if HAVE_READLINE_READLINE_H # include #endif #if HAVE_RL_ADD_HISTORY && HAVE_READLINE_HISTORY_H # include /* call add_history only if the line is non-blank */ static void do_add_history(const char *line) { if (line[strspn(line, " \t")]) add_history(line); } #else static void do_add_history(const char *line) { } #endif static const char *progname = "cdecl99"; static bool batch_mode; void print_error(const char *fmt, ...) { va_list(ap); fprintf(stderr, batch_mode ? "%s: %s" : "%.0s%s", progname, _("error: ")); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); } static void print_version(void) { do_print_version(PACKAGE_STRING); } static void print_usage(FILE *f) { fprintf(f, _("Usage: %s [options]\n"), progname); if (f != stdout) fprintf(f, _("Try %s --help for more information.\n"), progname); } static void print_help(const struct option *lopts) { struct lopt_help help = {0}; const struct option *opt; print_usage(stdout); puts(_("This is \"cdecl99\": a command-line tool for parsing and constructing\n" "complicated C declarations.")); putchar('\n'); puts(_("Options:")); for (opt = lopts; opt->name; opt++) { if (!lopt_get_help(opt, &help)) continue; help_print_option(opt, help.arg, help.desc, 20); } printf("\n%s\n\n", _("For more information, see the cdecl99(1) man page.")); /* * TRANSLATORS: Please add *another line* indicating where users should * report translation bugs. */ printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT); } static int do_readline(char **linebuf, size_t *n, bool batch) { #if !HAVE_READLINE if (!batch) { fputs("> ", stdout); fflush(stdout); } return do_getline(linebuf, n); #else if (batch) return do_getline(linebuf, n); free(*linebuf); if (!(*linebuf = readline("> "))) return 0; do_add_history(*linebuf); return 1; #endif } static int repl(bool batch) { char *line = NULL; bool fail = 0; size_t n = 0; while (do_readline(&line, &n, batch)) { int rc = run_command(line, batch); if (rc > 0) break; if (rc < 0) fail = batch; } free(line); return fail ? EXIT_FAILURE : 0; } static int repl_cmdline(unsigned count, char **commands) { bool fail = 0; unsigned i; for (i = 0; i < count; i++) { int rc = run_command(commands[i], true); if (rc > 0) break; if (rc < 0) fail = true; } return fail ? EXIT_FAILURE : 0; } /* Initialize gettext */ static void init_i18n(void) { if (!ENABLE_NLS) return; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); } enum { INIT_EXIT_SUCCESS = -1, INIT_EXIT_FAILURE = -2 }; static int initialize(int argc, char **argv) { int i, opt, quiet = 0, execute = 0; const char *filename = NULL; XTRA_PACKED_LOPTS(lopts); if (argc > 0) progname = argv[0]; init_i18n(); while ((opt = getopt_long(argc, argv, SOPT_STRING, lopts, 0)) != -1) { switch (opt) { case 'q': quiet = 1; break; case 'b': batch_mode = true; break; case 'i': batch_mode = false; break; case 'f': filename = optarg; break; case 'e': argv[execute++] = optarg; break; case 'V': print_version(); return INIT_EXIT_SUCCESS; case 'H': print_help(lopts); return INIT_EXIT_SUCCESS; default: print_usage(stderr); return INIT_EXIT_FAILURE; } } if (optind < argc) { fprintf(stderr, "%s: %s", progname, _("excess command-line arguments:")); for (i = optind; i < argc; i++) { fprintf(stderr, " %s", argv[i]); } fprintf(stderr, "\n"); print_usage(stderr); return INIT_EXIT_FAILURE; } /* --filename and --execute imply --batch. */ if (filename || execute) batch_mode = true; /* --batch implies --quiet */ if (!batch_mode && !quiet) print_version(); /* --execute supersedes --filename */ if (filename && !execute) { if (!freopen(filename, "r", stdin)) { print_error("failed to open %s: %s", filename, strerror(errno)); return INIT_EXIT_FAILURE; } } return execute; } int main(int argc, char **argv) { int execute; switch ((execute = initialize(argc, argv))) { case INIT_EXIT_SUCCESS: return EXIT_SUCCESS; case INIT_EXIT_FAILURE: return EXIT_FAILURE; } if (execute) return repl_cmdline(execute, argv); else return repl(batch_mode); }