X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fui%2Fterminal%2Fterminal-opts.c;h=929fd3878defb8c4f0a02b3f70982d1cc4ec7c8c;hb=c75794cffb05769b71a346af8513a3e8dde55f94;hp=955a6b0e9c7fda53e2daa1a9b67e9b528f2189bd;hpb=dfd1972f7bcb550a4fc3b05dbe7e71d12334b0a7;p=pspp diff --git a/src/ui/terminal/terminal-opts.c b/src/ui/terminal/terminal-opts.c index 955a6b0e9c..929fd3878d 100644 --- a/src/ui/terminal/terminal-opts.c +++ b/src/ui/terminal/terminal-opts.c @@ -1,5 +1,5 @@ /* PSPPIRE - a graphical user interface for PSPP. - Copyright (C) 2008 Free Software Foundation + Copyright (C) 2008, 2010 Free Software Foundation 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 @@ -18,197 +18,335 @@ #include "terminal-opts.h" -#include #include #include #include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include "data/settings.h" +#include "data/file-name.h" +#include "language/syntax-file.h" +#include "libpspp/argv-parser.h" +#include "libpspp/assertion.h" +#include "libpspp/compiler.h" +#include "libpspp/getl.h" +#include "libpspp/llx.h" +#include "libpspp/str.h" +#include "libpspp/string-array.h" +#include "libpspp/string-map.h" +#include "libpspp/string-set.h" +#include "libpspp/version.h" +#include "output/driver.h" +#include "output/driver-provider.h" +#include "output/msglog.h" +#include "ui/terminal/msg-ui.h" +#include "ui/terminal/read-line.h" #include "gl/error.h" +#include "gl/progname.h" +#include "gl/version-etc.h" +#include "gl/xmemdup0.h" #include "gettext.h" #define _(msgid) gettext (msgid) #define N_(msgid) msgid -static const struct argp_option test_options [] = +struct terminal_opts { - {"verbose", 'v', 0, 0, N_("Increase diagnostic verbosity level"), 0}, - {"testing-mode", 'T', 0, OPTION_HIDDEN, 0, 0}, + struct source_stream *source_stream; + enum syntax_mode syntax_mode; + struct string_map options; /* Output driver options. */ + bool has_output_driver; + bool has_terminal_driver; + bool has_error_file; + bool process_statrc; + }; - { 0, 0, 0, 0, 0, 0 } +enum + { + OPT_TESTING_MODE, + OPT_ERROR_FILE, + OPT_OUTPUT, + OPT_OUTPUT_OPTION, + OPT_NO_OUTPUT, + OPT_INTERACTIVE, + OPT_NO_STATRC, + OPT_HELP, + OPT_VERSION, + N_TERMINAL_OPTIONS }; -static error_t -parse_test_opts (int key, char *arg, struct argp_state *state) +static struct argv_option terminal_argv_options[N_TERMINAL_OPTIONS] = + { + {"testing-mode", 0, no_argument, OPT_TESTING_MODE}, + {"error-file", 'e', required_argument, OPT_ERROR_FILE}, + {"output", 'o', required_argument, OPT_OUTPUT}, + {NULL, 'O', required_argument, OPT_OUTPUT_OPTION}, + {"no-output", 0, no_argument, OPT_NO_OUTPUT}, + {"interactive", 'i', no_argument, OPT_INTERACTIVE}, + {"no-statrc", 'r', no_argument, OPT_NO_STATRC}, + {"help", 'h', no_argument, OPT_HELP}, + {"version", 'V', no_argument, OPT_VERSION}, + }; + +static void +register_output_driver (struct terminal_opts *to) { - switch (key) + if (!string_map_is_empty (&to->options)) { - case 'T': - settings_set_testing_mode (true); - break; - case 'v': - verbose_increment_level (); - break; - default: - return ARGP_ERR_UNKNOWN; - } - - return 0; -} + struct output_driver *driver; -static const struct argp_option io_options [] = - { - {"error-file", 'e', "FILE", 0, - N_("Send error messages to FILE (appended)"), 0}, + driver = output_driver_create (&to->options); + if (driver != NULL) + { + output_driver_register (driver); - {"device", 'o', "DEVICE", 0, - N_("Select output driver DEVICE and disable defaults"), 0}, + to->has_output_driver = true; + if (driver->device_type == SETTINGS_DEVICE_TERMINAL) + to->has_terminal_driver = true; + } + string_map_clear (&to->options); + } +} - {"list", 'l', 0, 0, - N_("Print a list of known driver classes, then exit"), 0}, +static void +parse_output_option (struct terminal_opts *to, const char *option) +{ + const char *equals; + char *key, *value; - {"interactive", 'i', 0, 0, N_("Start an interactive session"), 0}, + equals = strchr (option, '='); + if (equals == NULL) + { + error (0, 0, _("%s: output option missing `='"), option); + return; + } - { 0, 0, 0, 0, 0, 0 } - }; + key = xmemdup0 (option, equals - option); + if (string_map_contains (&to->options, key)) + { + error (0, 0, _("%s: output option specified more than once"), key); + free (key); + return; + } + value = xmemdup0 (equals + 1, strlen (equals + 1)); + string_map_insert_nocopy (&to->options, key, value); +} -static error_t -parse_io_opts (int key, char *arg, struct argp_state *state) +static char * +get_supported_formats (void) { - struct source_init - { - struct llx_list file_list; - bool interactive; - - /* Output devices. */ - struct string_map macros; - struct string_set drivers; - }; - - struct fn_element { - struct ll ll; - const char *fn; - }; + const struct string_set_node *node; + struct string_array format_array; + struct string_set format_set; + char *format_string; + const char *format; + size_t i; + + /* Get supported formats as unordered set. */ + string_set_init (&format_set); + output_get_supported_formats (&format_set); + + /* Converted supported formats to sorted array. */ + string_array_init (&format_array); + STRING_SET_FOR_EACH (format, node, &format_set) + string_array_append (&format_array, format); + string_array_sort (&format_array); + string_set_destroy (&format_set); + + /* Converted supported formats to string. */ + format_string = string_array_join (&format_array, " "); + string_array_destroy (&format_array); + return format_string; +} - struct source_init *sip = state->hook; +static char * +get_default_include_path (void) +{ + struct source_stream *ss; + struct string dst; + char **path; + size_t i; + + ss = create_source_stream (); + path = getl_include_path (ss); + ds_init_empty (&dst); + for (i = 0; path[i] != NULL; i++) + ds_put_format (&dst, " %s", path[i]); + destroy_source_stream (ss); + + return ds_steal_cstr (&dst); +} - struct source_stream *ss = state->input; +static void +usage (void) +{ + char *supported_formats = get_supported_formats (); + char *default_include_path = get_default_include_path (); + + printf (_("\ +PSPP, a program for statistical analysis of sample data.\n\ +Usage: %s [OPTION]... FILE...\n\ +\n\ +Arguments to long options also apply to equivalent short options.\n\ +\n\ +Output options:\n\ + -o, --output=FILE output to FILE, default format from FILE's name\n\ + -O format=FORMAT override format for previous -o\n\ + -O OPTION=VALUE set output option to customize previous -o\n\ + -O device={terminal|listing} override device type for previous -o\n\ + -e, --error-file=FILE append errors, warnings, and notes to FILE\n\ + --no-output disable default output driver\n\ +Supported output formats: %s\n\ +\n\ +Language options:\n\ + -I, --include=DIR append DIR to search path\n\ + -I-, --no-include clear search path\n\ + -r, --no-statrc disable running rc file at startup\n\ + -a, --algorithm={compatible|enhanced}\n\ + set to `compatible' if you want output\n\ + calculated from broken algorithms\n\ + -x, --syntax={compatible|enhanced}\n\ + set to `compatible' to disable PSPP extensions\n\ + -i, --interactive interpret syntax in interactive mode\n\ + -s, --safer don't allow some unsafe operations\n\ +Default search path:%s\n\ +\n\ +Informative output:\n\ + -h, --help display this help and exit\n\ + -V, --version output version information and exit\n\ +\n\ +Non-option arguments are interpreted as syntax files to execute.\n"), + program_name, supported_formats, default_include_path); + + free (supported_formats); + free (default_include_path); + + emit_bug_reporting_address (); + exit (EXIT_SUCCESS); +} - struct command_line_processor *clp = get_subject (state); +static void +terminal_option_callback (int id, void *to_) +{ + struct terminal_opts *to = to_; - switch (key) + switch (id) { - case ARGP_KEY_INIT: - state->hook = sip = xzalloc (sizeof (struct source_init)); - llx_init (&sip->file_list); - string_map_init (&sip->macros); - string_set_init (&sip->drivers); - break; - case ARGP_KEY_ARG: - if (strchr (arg, '=')) - { - if (!output_define_macro (arg, &sip->macros)) - error (0, 0, _("\"%s\" is not a valid macro definition"), arg); - } - else - { - llx_push_tail (&sip->file_list, arg, &llx_malloc_mgr); - } + case OPT_TESTING_MODE: + settings_set_testing_mode (true); break; - case ARGP_KEY_SUCCESS: - { - struct llx *llx = llx_null (&sip->file_list); - while ((llx = llx_next (llx)) != llx_null (&sip->file_list)) - { - const char *fn = llx_data (llx); - /* Assume it's a syntax file */ - getl_append_source (ss, - create_syntax_file_source (fn), - GETL_BATCH, - ERRMODE_CONTINUE - ); - - } - - if (sip->interactive || llx_is_empty (&sip->file_list)) - { - getl_append_source (ss, create_readln_source (), - GETL_INTERACTIVE, - ERRMODE_CONTINUE - ); - - string_set_insert (&sip->drivers, "interactive"); - } - - if (!settings_get_testing_mode ()) - output_read_configuration (&sip->macros, &sip->drivers); - else - output_configure_driver ("csv:csv::"); - - string_map_destroy (&sip->macros); - string_set_destroy (&sip->drivers); - } + + case OPT_ERROR_FILE: + if (!strcmp (optarg, "none") || msglog_create (optarg)) + to->has_error_file = true; break; - case ARGP_KEY_FINI: - free (sip); + + case OPT_OUTPUT: + register_output_driver (to); + string_map_insert (&to->options, "output-file", optarg); break; - case 'e': - msg_ui_set_error_file (arg); + + case OPT_OUTPUT_OPTION: + parse_output_option (to, optarg); break; - case 'i': - sip->interactive = true; + + case OPT_NO_OUTPUT: + /* Pretend that we already have an output driver, which disables adding + one in terminal_opts_done() when we don't already have one. */ + to->has_output_driver = true; break; - case 'l': - output_list_classes (); + + case OPT_INTERACTIVE: + to->syntax_mode = GETL_INTERACTIVE; break; - case 'o': - string_set_insert (&sip->drivers, arg); + + case OPT_NO_STATRC: + to->process_statrc = false; break; + + case OPT_HELP: + usage (); + exit (EXIT_SUCCESS); + + case OPT_VERSION: + version_etc (stdout, "pspp", PACKAGE_NAME, PACKAGE_VERSION, + "Ben Pfaff", "John Darrington", "Jason Stover", + NULL); + exit (EXIT_SUCCESS); + default: - return ARGP_ERR_UNKNOWN; + NOT_REACHED (); } - - return 0; } -const struct argp io_argp = {io_options, parse_io_opts, 0, 0, 0, 0, 0}; -const struct argp test_argp = {test_options, parse_test_opts, 0, 0, 0, 0, 0}; - -#if 0 -static const struct argp_child children [] = - { - {&io_argp, 0, N_("Options affecting input and output locations:"), 0}, - {&test_argp, 0, N_("Diagnostic options:"), 0}, - {0, 0, 0, 0} - }; +struct terminal_opts * +terminal_opts_init (struct argv_parser *ap, struct source_stream *ss) +{ + struct terminal_opts *to; + + to = xzalloc (sizeof *to); + to->source_stream = ss; + to->syntax_mode = GETL_BATCH; + string_map_init (&to->options); + to->has_output_driver = false; + to->has_error_file = false; + to->process_statrc = true; + + argv_parser_add_options (ap, terminal_argv_options, N_TERMINAL_OPTIONS, + terminal_option_callback, to); + return to; +} +static void +add_syntax_file (struct terminal_opts *to, const char *file_name) +{ + if (!strcmp (file_name, "-") && isatty (STDIN_FILENO)) + getl_append_source (to->source_stream, create_readln_source (), + GETL_INTERACTIVE, ERRMODE_CONTINUE); + else + getl_append_source (to->source_stream, + create_syntax_file_source (file_name), + to->syntax_mode, ERRMODE_CONTINUE); +} -static error_t -propagate_aux (int key, char *arg, struct argp_state *state) +void +terminal_opts_done (struct terminal_opts *to, int argc, char *argv[]) { - if ( key == ARGP_KEY_INIT) + if (to->process_statrc) + { + char *rc = fn_search_path ("rc", getl_include_path (to->source_stream)); + if (rc != NULL) + { + getl_append_source (to->source_stream, + create_syntax_file_source (rc), GETL_BATCH, + ERRMODE_CONTINUE); + free (rc); + } + } + + if (optind < argc) { int i; - for (i = 0 ; i < sizeof (children) / sizeof (children[0]) - 1 ; ++i) - state->child_inputs[i] = state->input; + + for (i = optind; i < argc; i++) + add_syntax_file (to, argv[i]); } + else + add_syntax_file (to, "-"); - return ARGP_ERR_UNKNOWN; -} + register_output_driver (to); + if (!to->has_output_driver) + { + string_map_insert (&to->options, "output-file", "-"); + string_map_insert (&to->options, "format", "txt"); + register_output_driver (to); + } -const struct argp terminal_argp = {NULL, propagate_aux, 0, 0, children, 0, 0}; + if (!to->has_terminal_driver && !to->has_error_file) + msglog_create ("-"); -#endif + string_map_destroy (&to->options); + free (to); +}