/* 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
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
-#include <argp.h>
+
+#include "terminal-opts.h"
+
#include <stdbool.h>
-#include <xalloc.h>
#include <stdlib.h>
-#include <data/settings.h>
-#include <output/output.h>
-#include "msg-ui.h"
-#include <ui/command-line.h>
-#include <libpspp/verbose-msg.h>
-#include <libpspp/llx.h>
-#include <data/file-name.h>
-#include "terminal-opts.h"
-#include <libpspp/getl.h>
-#include <language/syntax-file.h>
-#include "read-line.h"
+#include <string.h>
+
+#include "data/settings.h"
+#include "language/lexer/include-path.h"
+#include "libpspp/argv-parser.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/compiler.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 "output/pivot-table.h"
+
+#include "gl/error.h"
+#include "gl/localcharset.h"
+#include "gl/progname.h"
+#include "gl/version-etc.h"
+#include "gl/xmemdup0.h"
+#include "gl/xalloc.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
#define N_(msgid) msgid
+struct terminal_opts
+ {
+ struct string_map options; /* Output driver options. */
+ bool has_output_driver;
+ bool has_terminal_driver;
+ bool has_error_file;
+ enum lex_syntax_mode *syntax_mode;
+ bool *process_statrc;
+ char **syntax_encoding;
+ char *table_look;
+ };
-static const struct argp_option test_options [] =
+enum
{
- {"verbose", 'v', 0, 0, N_("Increase diagnostic verbosity level"), 0},
- {"testing-mode", 'T', 0, OPTION_HIDDEN, 0, 0},
+ OPT_TESTING_MODE,
+ OPT_ERROR_FILE,
+ OPT_OUTPUT,
+ OPT_OUTPUT_OPTION,
+ OPT_NO_OUTPUT,
+ OPT_BATCH,
+ OPT_INTERACTIVE,
+ OPT_SYNTAX_ENCODING,
+ OPT_NO_STATRC,
+ OPT_TABLE_LOOK,
+ OPT_HELP,
+ OPT_VERSION,
+ N_TERMINAL_OPTIONS
+ };
- { 0, 0, 0, 0, 0, 0 }
+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},
+ {"batch", 'b', no_argument, OPT_BATCH},
+ {"interactive", 'i', no_argument, OPT_INTERACTIVE},
+ {"syntax-encoding", 0, required_argument, OPT_SYNTAX_ENCODING},
+ {"no-statrc", 'r', no_argument, OPT_NO_STATRC},
+ {"table-look", 0, required_argument, OPT_TABLE_LOOK},
+ {"help", 'h', no_argument, OPT_HELP},
+ {"version", 'V', no_argument, OPT_VERSION},
};
-static error_t
-parse_test_opts (int key, char *arg, struct argp_state *state)
+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;
+ struct output_driver *driver;
+
+ driver = output_driver_create (&to->options);
+ if (driver != NULL)
+ {
+ output_driver_register (driver);
+
+ to->has_output_driver = true;
+ if (driver->device_type == SETTINGS_DEVICE_TERMINAL)
+ to->has_terminal_driver = true;
+ }
+ string_map_clear (&to->options);
}
-
- return 0;
}
-static const struct argp_option io_options [] =
- {
- {"error-file", 'e', "FILE", 0,
- N_("Send error messages to FILE (appended)"), 0},
-
- {"device", 'o', "DEVICE", 0,
- N_("Select output driver DEVICE and disable defaults"), 0},
-
- {"list", 'l', 0, 0,
- N_("Print a list of known driver classes, then exit"), 0},
-
- {"interactive", 'i', 0, 0, N_("Start an interactive session"), 0},
-
- { 0, 0, 0, 0, 0, 0 }
- };
-
-
-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 cleared_device_defaults;
- bool interactive;
- };
+ const struct string_set_node *node;
+ struct string_array format_array;
+ struct string_set format_set;
+ char *format_string;
+ const char *format;
+
+ /* 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 fn_element {
- struct ll ll;
- const char *fn;
- };
+static void
+usage (void)
+{
+ char *supported_formats = get_supported_formats ();
+ char *inc_path = string_array_join (include_path_default (), " ");
+
+ printf (_("\
+PSPP, a program for statistical analysis of sampled 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\
+ --table-look=FILE use output style read from FILE\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\
+ -b, --batch interpret syntax in batch mode\n\
+ -i, --interactive interpret syntax in interactive mode\n\
+ --syntax-encoding=ENCODING specify encoding for syntax files\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, inc_path);
+
+ free (supported_formats);
+ free (inc_path);
+
+ emit_bug_reporting_address ();
+ exit (EXIT_SUCCESS);
+}
- struct source_init *sip = state->hook;
+static void
+terminal_option_callback (int id, void *to_)
+{
+ struct terminal_opts *to = to_;
- struct source_stream *ss = state->input;
+ switch (id)
+ {
+ case OPT_TESTING_MODE:
+ settings_set_testing_mode (true);
+ break;
- struct command_line_processor *clp = get_subject (state);
+ case OPT_ERROR_FILE:
+ if (!strcmp (optarg, "none") || msglog_create (optarg))
+ to->has_error_file = true;
+ break;
- switch (key)
- {
- case ARGP_KEY_INIT:
- state->hook = sip = xzalloc (sizeof (struct source_init));
- llx_init (&sip->file_list);
+ case OPT_OUTPUT:
+ register_output_driver (to);
+ string_map_insert (&to->options, "output-file", optarg);
break;
- case ARGP_KEY_ARG:
- if (strchr (arg, '='))
- outp_configure_macro (arg);
- else
- {
- llx_push_tail (&sip->file_list, arg, &llx_malloc_mgr);
- }
+
+ case OPT_OUTPUT_OPTION:
+ output_driver_parse_option (optarg, &to->options);
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
- );
-
- if (!sip->cleared_device_defaults)
- outp_configure_add ("interactive");
- }
- }
+
+ 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 ARGP_KEY_FINI:
- free (sip);
+
+ case OPT_BATCH:
+ *to->syntax_mode = LEX_SYNTAX_BATCH;
break;
- case 'e':
- msg_ui_set_error_file (arg);
+
+ case OPT_INTERACTIVE:
+ *to->syntax_mode = LEX_SYNTAX_INTERACTIVE;
break;
- case 'i':
- sip->interactive = true;
+
+ case OPT_SYNTAX_ENCODING:
+ *to->syntax_encoding = optarg;
break;
- case 'l':
- outp_list_classes ();
+
+ case OPT_NO_STATRC:
+ *to->process_statrc = false;
break;
- case 'o':
- if (! sip->cleared_device_defaults)
- {
- outp_configure_clear ();
- sip->cleared_device_defaults = true;
- }
- outp_configure_add (arg);
+
+ case OPT_TABLE_LOOK:
+ to->table_look = optarg;
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_SENTINEL);
+ exit (EXIT_SUCCESS);
+
default:
- return ARGP_ERR_UNKNOWN;
+ NOT_REACHED ();
}
+}
- return 0;
+struct terminal_opts *
+terminal_opts_init (struct argv_parser *ap,
+ enum lex_syntax_mode *syntax_mode, bool *process_statrc,
+ char **syntax_encoding)
+{
+ struct terminal_opts *to;
+
+ *syntax_mode = LEX_SYNTAX_AUTO;
+ *process_statrc = true;
+ *syntax_encoding = "Auto";
+
+ to = xzalloc (sizeof *to);
+ to->syntax_mode = syntax_mode;
+ string_map_init (&to->options);
+ to->has_output_driver = false;
+ to->has_error_file = false;
+ to->syntax_mode = syntax_mode;
+ to->process_statrc = process_statrc;
+ to->syntax_encoding = syntax_encoding;
+
+ argv_parser_add_options (ap, terminal_argv_options, N_TERMINAL_OPTIONS,
+ terminal_option_callback, to);
+ return to;
}
-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};
+void
+terminal_opts_done (struct terminal_opts *to, int argc, char *argv[])
+{
+ 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);
+ }
-#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}
- };
+ if (!to->has_terminal_driver && !to->has_error_file)
+ msglog_create ("-");
+ string_map_destroy (&to->options);
-static error_t
-propagate_aux (int key, char *arg, struct argp_state *state)
-{
- if ( key == ARGP_KEY_INIT)
+ if (to->table_look)
{
- int i;
- for (i = 0 ; i < sizeof (children) / sizeof (children[0]) - 1 ; ++i)
- state->child_inputs[i] = state->input;
+ struct pivot_table_look *look;
+ char *s = pivot_table_look_read (to->table_look, &look);
+ if (s)
+ error (1, 0, "%s", s);
+ pivot_table_look_set_default (look);
+ pivot_table_look_unref (look);
}
- return ARGP_ERR_UNKNOWN;
+ free (to);
}
-
-const struct argp terminal_argp = {NULL, propagate_aux, 0, 0, children, 0, 0};
-
-#endif