/* * Command line utility for making sense of C declarations. * Copyright © 2011-2012, 2020-2023 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 #include "cdecl99.h" #include "cdecl.h" #include "help.h" #include "xtra.h" #include "copysym.h" #include "options.h" static const char *progname = "cdecl99"; static bool interactive = true; void print_error(const char *fmt, ...) { va_list(ap); if (!interactive) fprintf(stderr, "%s: ", progname); fprintf(stderr, "%s", _("error: ")); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); } static void print_version(void) { const char *copysign = copyright_symbol(locale_charset()); puts(PACKAGE_STRING); printf("Copyright %s 2023 Nick Bowler.\n", copysign); puts("License GPLv3+: GNU GPL version 3 or any later version."); puts("This is free software: you are free to change and redistribute it."); puts("There is NO WARRANTY, to the extent permitted by law."); } 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); } putchar('\n'); puts(_("For more information, see the cdecl99(1) man page.")); putchar('\n'); /* * TRANSLATORS: Please add *another line* indicating where users should * report translation bugs. */ printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT); } static int is_blank_line(const char *line) { return !line[strspn(line, " \t")]; } static int repl(void) { char *line; for (; (line = readline("> ")); free(line)) { if (!is_blank_line(line)) add_history(line); if (run_command(line, true) > 0) break; } free(line); return 0; } static int repl_cmdline(unsigned count, char **commands) { int ret = 0; unsigned i; for (i = 0; i < count; i++) { int rc = run_command(commands[i], false); if (rc < 0) ret = -1; else if (rc > 0) break; } return ret; } static int repl_noninteractive(void) { int rc, ret = 0, saved_errno; char *line = NULL; size_t n; while (getline(&line, &n, stdin) >= 0) { char *c = strchr(line, '\n'); if (c) *c = '\0'; rc = run_command(line, false); if (rc < 0) ret = -1; else if (rc > 0) break; } saved_errno = errno; free(line); if (ferror(stdin)) { print_error("%s", strerror(saved_errno)); return -1; } return ret; } /* 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': interactive = false; break; case 'i': interactive = true; 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: ", progname); fprintf(stderr, _("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) interactive = false; /* --batch implies --quiet */ if (interactive && !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 rc, execute; switch ((execute = initialize(argc, argv))) { case INIT_EXIT_SUCCESS: return EXIT_SUCCESS; case INIT_EXIT_FAILURE: return EXIT_FAILURE; } if (interactive) rc = repl(); else if (execute) rc = repl_cmdline(execute, argv); else rc = repl_noninteractive(); if (rc != 0) return EXIT_FAILURE; return EXIT_SUCCESS; }