From fe76b9c2c49a0dd33aad5dfe3f03a056e6f96c21 Mon Sep 17 00:00:00 2001 From: John Darrington Date: Sat, 8 Nov 2008 12:44:56 +0900 Subject: [PATCH] Rewrote the command line parser using argp. Reimplemented the command line parser using argp. Removed some unimplemented options and added the ability for the gui to open system or portable files whose names are specified on the command line. --- Smake | 1 + doc/invoking.texi | 37 +-- src/ui/automake.mk | 8 +- src/ui/command-line.c | 166 +++++++++++ src/ui/command-line.h | 36 +++ src/ui/gui/main.c | 134 +++++---- src/ui/gui/psppire.c | 81 +++++- src/ui/gui/psppire.h | 7 +- src/ui/source-init-opts.c | 136 +++++++++ .../command-line.h => source-init-opts.h} | 14 +- src/ui/terminal/automake.mk | 7 +- src/ui/terminal/command-line.c | 274 ------------------ src/ui/terminal/main.c | 84 ++++-- src/ui/terminal/terminal-opts.c | 198 +++++++++++++ src/ui/terminal/terminal-opts.h | 27 ++ 15 files changed, 785 insertions(+), 425 deletions(-) create mode 100644 src/ui/command-line.c create mode 100644 src/ui/command-line.h create mode 100644 src/ui/source-init-opts.c rename src/ui/{terminal/command-line.h => source-init-opts.h} (68%) delete mode 100644 src/ui/terminal/command-line.c create mode 100644 src/ui/terminal/terminal-opts.c create mode 100644 src/ui/terminal/terminal-opts.h diff --git a/Smake b/Smake index 3994a302..7905c430 100644 --- a/Smake +++ b/Smake @@ -5,6 +5,7 @@ GNULIB = ../gnulib GNULIB_TOOL = $(GNULIB)/gnulib-tool GNULIB_MODULES = \ + argp \ assert \ byteswap \ c-ctype \ diff --git a/doc/invoking.texi b/doc/invoking.texi index b5f157e6..d7619358 100644 --- a/doc/invoking.texi +++ b/doc/invoking.texi @@ -7,12 +7,12 @@ @cindex options, command-line @example pspp [ -B @var{dir} | --config-dir=@var{dir} ] [ -o @var{device} | --device=@var{device} ] - [ -d @var{var}[=@var{value}] | --define=@var{var}[=@var{value}] ] [-u @var{var} | --undef=@var{var} ] - [ -f @var{file} | --out-file=@var{file} ] [ -p | --pipe ] [ -I- | --no-include ] + [ -a @{compatible|enhanced@} | --algorithm=@{compatible|enhanced@}] + [ -x @{compatible|enhanced@} | --syntax=@{compatible|enhanced@}] + [ -I- | --no-include ] [ -I @var{dir} | --include=@var{dir} ] [ -i | --interactive ] - [ -n | --edit | --dry-run | --just-print | --recon ] [ -r | --no-statrc ] [ -h | --help ] [ -l | --list ] - [ -c @var{command} | --command @var{command} ] [ -s | --safer ] + [ -s | --safer ] [ --testing-mode ] [ -V | --version ] [ -v | --verbose ] [ @var{key}=@var{value} ] @var{file}@enddots{} @end example @@ -101,19 +101,6 @@ Input and output options affect how PSPP reads input and writes output. These are the input and output options: @table @code -@item -f @var{file} -@itemx --out-file=@var{file} - -This overrides the output file name for devices designated as listing -devices. If a file named @var{file} already exists, it is overwritten. - -@item -p -@itemx --pipe - -Allows PSPP to be used as a filter by causing the syntax file to be -read from stdin and output to be written to stdout. Conflicts with the -@code{-f @var{file}} and @code{--file=@var{file}} options. - @item -I- @itemx --no-include @@ -127,12 +114,6 @@ configuring}. Appends directory @var{dir} to the path that is searched for include files in PSPP syntax files. -@item -c @var{command} -@itemx --command=@var{command} - -Execute literal command @var{command}. The command is executed before -startup syntax files, if any. - @item --testing-mode Invoke heuristics to assist with testing PSPP. For use by @code{make @@ -158,16 +139,6 @@ mode, rather than the default batch mode. @xref{Tokenizing lines}, for information on the differences between batch mode and interactive mode command interpretation. -@item -n -@itemx --edit -@itemx --dry-run -@itemx --just-print -@itemx --recon - -Only the syntax of any syntax file specified or of commands entered at -the command line is checked. Transformations are not performed and -procedures are not executed. Not yet implemented. - @item -r @itemx --no-statrc diff --git a/src/ui/automake.mk b/src/ui/automake.mk index f1dde68a..c21b681d 100644 --- a/src/ui/automake.mk +++ b/src/ui/automake.mk @@ -9,9 +9,9 @@ endif noinst_LTLIBRARIES += src/ui/libuicommon.la src_ui_libuicommon_la_SOURCES = \ - src/ui/debugger.c \ - src/ui/debugger.h \ - src/ui/syntax-gen.c \ - src/ui/syntax-gen.h + src/ui/command-line.c src/ui/command-line.h \ + src/ui/debugger.c src/ui/debugger.h \ + src/ui/source-init-opts.c src/ui/source-init-opts.h \ + src/ui/syntax-gen.c src/ui/syntax-gen.h EXTRA_DIST += src/ui/OChangeLog diff --git a/src/ui/command-line.c b/src/ui/command-line.c new file mode 100644 index 00000000..46dddd49 --- /dev/null +++ b/src/ui/command-line.c @@ -0,0 +1,166 @@ +/* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2008 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 + 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 "command-line.h" +#include +#include +#include +#include +#include +#include + + +struct clp_child +{ + void *aux; +}; + +struct command_line_processor +{ + struct argp master_parser; + + struct clp_child *child_lookup_table; + struct argp_child *children; + int n_children; + + const char *doc; + const char *args_doc; + + void *aux; +}; + + +/* Convenience function for use in parsing functions. + Returns the object for this parser */ +struct command_line_processor * +get_subject (struct argp_state *state) +{ + const struct argp *root = state->root_argp; + + const struct argp_child *children = root->children; + + return (struct command_line_processor *) children[0].argp; +} + + +/* Create a command line processor. + DOC is typically the name of the program and short description. + ARGS_DOC is a short description of the non option arguments. + AUX is an arbitrary pointer. + */ +struct command_line_processor * +command_line_processor_create (const char *doc, const char *args_doc, void *aux) +{ + struct command_line_processor *clp = xzalloc (sizeof (*clp)); + + clp->children = NULL; + clp->child_lookup_table = NULL; + + clp->doc = doc; + clp->args_doc = args_doc; + clp->aux = aux; + + return clp; +} + +/* Destroy a command line processor */ +void +command_line_processor_destroy (struct command_line_processor *clp) +{ + free (clp->children); + free (clp->child_lookup_table); + free (clp); +} + + +/* Add a CHILD to the processor CLP, with the doc string DOC. + AUX is an auxilliary pointer, specific to CHILD. + If AUX is not known or not needed then it may be set to NULL +*/ +void +command_line_processor_add_options (struct command_line_processor *clp, const struct argp *child, + const char *doc, void *aux) +{ + clp->n_children++; + + clp->children = xrealloc (clp->children, (clp->n_children + 1) * sizeof (*clp->children)); + memset (&clp->children[clp->n_children - 1], 0, sizeof (*clp->children)); + + clp->child_lookup_table = xrealloc (clp->child_lookup_table, + clp->n_children * sizeof (*clp->child_lookup_table)); + + clp->child_lookup_table [clp->n_children - 1].aux = aux; + + clp->children [clp->n_children - 1].argp = child; + clp->children [clp->n_children - 1].header = doc; + clp->children [clp->n_children].argp = NULL; +} + + +/* Set the aux paramter for CHILD in CLP to AUX. + Any previous value will be overwritten. + */ +void +command_line_processor_replace_aux (struct command_line_processor *clp, const struct argp *child, void *aux) +{ + int i; + for (i = 0 ; i < clp->n_children; ++i ) + { + if (child->options == clp->children[i].argp->options) + { + clp->child_lookup_table[i].aux = aux; + break; + } + } + assert (i < clp->n_children); +} + + +static error_t +top_level_parser (int key UNUSED, char *arg UNUSED, struct argp_state *state) +{ + int i; + struct command_line_processor *clp = state->input; + + if ( key == ARGP_KEY_INIT) + { + + for (i = 0; i < clp->n_children ; ++i) + { + state->child_inputs[i] = clp->child_lookup_table[i].aux; + } + } + + return ARGP_ERR_UNKNOWN; +} + + +/* Parse the command line specified by (ARGC, ARGV) using CLP */ +void +command_line_processor_parse (struct command_line_processor *clp, int argc, char **argv) +{ + clp->master_parser.parser = top_level_parser; + clp->master_parser.args_doc = clp->args_doc; + + clp->master_parser.doc = clp->doc; + + clp->master_parser.children = clp->children; + + argp_parse (&clp->master_parser, argc, argv, 0, 0, clp); +} + diff --git a/src/ui/command-line.h b/src/ui/command-line.h new file mode 100644 index 00000000..98edbea1 --- /dev/null +++ b/src/ui/command-line.h @@ -0,0 +1,36 @@ +/* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2008 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 + 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 . */ + +#ifndef SRC_UI_COMMAND_LINE_H +#define SRC_UI_COMMAND_LINE_H + +#include + +struct command_line_processor; + +struct command_line_processor * get_subject (struct argp_state *state); + +struct command_line_processor *command_line_processor_create (const char *, const char *, void *); + +void command_line_processor_add_options (struct command_line_processor *cla, const struct argp *child, const char *doc, void *aux); + +void command_line_processor_replace_aux (struct command_line_processor *cla, const struct argp *child, void *aux); + +void command_line_processor_destroy (struct command_line_processor *); + +void command_line_processor_parse (struct command_line_processor *, int argc, char **argv); + +#endif diff --git a/src/ui/gui/main.c b/src/ui/gui/main.c index f68f2ad6..a36e9410 100644 --- a/src/ui/gui/main.c +++ b/src/ui/gui/main.c @@ -19,16 +19,49 @@ #include "psppire.h" #include "progname.h" #include -#include +#include #include +#include +#include #include #include -static gboolean parse_command_line (int *argc, char ***argv, gchar **filename, - gboolean *show_splash, GError **err); +#include "gettext.h" +#define _(msgid) gettext (msgid) +#define N_(msgid) msgid +const char *argp_program_version = version; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; + +/* Arguments to be interpreted before the X server gets initialised */ + +static const struct argp_option startup_options [] = + { + {"no-splash", 'q', 0, 0, N_("Don't show the splash screen"), 0 }, + { 0, 0, 0, 0, 0, 0 } + }; + +static error_t +parse_startup_opts (int key, char *arg, struct argp_state *state) +{ + gboolean *showsplash = state->input; + + switch (key) + { + case 'q': + *showsplash = FALSE; + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static const struct argp startup_argp = {startup_options, parse_startup_opts, 0, 0, 0, 0, 0}; + + static GtkWidget * create_splash_window (void) @@ -72,13 +105,22 @@ quit_one_loop (gpointer data) return FALSE; } +struct initialisation_parameters +{ + int argc; + char **argv; + GtkWidget *splash_window; + struct command_line_processor *clp; +}; + static gboolean run_inner_loop (gpointer data) { - initialize (); + struct initialisation_parameters *ip = data; + initialize (ip->clp, ip->argc, ip->argv); - g_timeout_add (500, hide_splash_window, data); + g_timeout_add (500, hide_splash_window, ip->splash_window); gtk_main (); @@ -92,10 +134,10 @@ run_inner_loop (gpointer data) int main (int argc, char *argv[]) { - GtkWidget *splash_window; - gchar *filename = 0; + struct command_line_processor *clp ; + struct initialisation_parameters init_p; gboolean show_splash = TRUE; - GError *err = 0; + const gchar *vers; set_program_name (argv[0]); @@ -113,75 +155,29 @@ main (int argc, char *argv[]) g_warning (vers); } - /* Deal with options like --version, --help etc */ - if ( ! parse_command_line (&argc, &argv, &filename, &show_splash, &err) ) - { - g_clear_error (&err); - return 0; - } + clp = command_line_processor_create (_("PSPPIRE --- A user interface for PSPP"), "[ DATA-FILE ]", 0); + + command_line_processor_add_options (clp, &startup_argp, _("Miscellaneous options:"), &show_splash); + command_line_processor_add_options (clp, &post_init_argp, + _("Options affecting syntax and behavior:"), NULL); + command_line_processor_add_options (clp, &non_option_argp, NULL, NULL); + + command_line_processor_parse (clp, argc, argv); gdk_init (&argc, &argv); - splash_window = create_splash_window (); + init_p.splash_window = create_splash_window (); + init_p.argc = argc; + init_p.argv = argv; + init_p.clp = clp; + if ( show_splash ) - gtk_widget_show (splash_window); + gtk_widget_show (init_p.splash_window); g_idle_add (quit_one_loop, 0); - gtk_quit_add (0, run_inner_loop, splash_window); + gtk_quit_add (0, run_inner_loop, &init_p); gtk_main (); - return 0; } - - -/* Parses the command line specified by ARGC and ARGV as received by - main (). Returns true if normal execution should proceed, - false if the command-line indicates that PSPP should exit. */ -static gboolean -parse_command_line (int *argc, char ***argv, gchar **filename, - gboolean *show_splash, GError **err) -{ - - static struct option long_options[] = - { - {"help", no_argument, NULL, 'h'}, - {"version", no_argument, NULL, 'V'}, - {"no-splash", no_argument, NULL, 'q'}, - {0, 0, 0, 0}, - }; - - int c; - - for (;;) - { - c = getopt_long (*argc, *argv, "hVq", long_options, NULL); - if (c == -1) - break; - - switch (c) - { - case 'h': - g_print ("Usage: psppire {|--help|--version|--no-splash}\n"); - return FALSE; - case 'V': - g_print (version); - g_print ("\n"); - g_print (legal); - return FALSE; - case 'q': - *show_splash = FALSE; - break; - default: - return FALSE; - } - } - - if ( optind < *argc) - { - *filename = (*argv)[optind]; - } - - return TRUE; -} diff --git a/src/ui/gui/psppire.c b/src/ui/gui/psppire.c index 04677463..b1551fbb 100644 --- a/src/ui/gui/psppire.c +++ b/src/ui/gui/psppire.c @@ -22,11 +22,14 @@ #include #include +#include +#include #include "relocatable.h" #include "data-editor.h" #include "psppire.h" +#include #include #include #include @@ -39,6 +42,7 @@ #include #include #include +#include #include #include @@ -47,9 +51,15 @@ #include "psppire-data-store.h" #include "helper.h" #include "message-dialog.h" +#include #include "output-viewer.h" +#include +#include + +#include + PsppireDataStore *the_data_store = 0; PsppireVarStore *the_var_store = 0; @@ -70,9 +80,8 @@ replace_casereader (struct casereader *s) #define _(msgid) gettext (msgid) #define N_(msgid) msgid - void -initialize (void) +initialize (struct command_line_processor *clp, int argc, char **argv) { PsppireDict *dictionary = 0; @@ -110,6 +119,8 @@ initialize (void) the_data_store = psppire_data_store_new (dictionary); replace_casereader (NULL); + + create_icon_factory (); outp_configure_driver_line ( @@ -126,7 +137,14 @@ initialize (void) /* Ignore alarm clock signals */ signal (SIGALRM, SIG_IGN); + command_line_processor_replace_aux (clp, &post_init_argp, the_source_stream); + command_line_processor_replace_aux (clp, &non_option_argp, the_source_stream); + + command_line_processor_parse (clp, argc, argv); + new_data_window (NULL, NULL); + + execute_syntax (create_syntax_string_source ("")); } @@ -201,11 +219,11 @@ create_icon_factory (void) gtk_stock_add (items, 2); - gtk_icon_factory_add (factory, "pspp-stock-reset", + gtk_icon_factory_add (factory, "pspp-stock-reset", gtk_icon_factory_lookup_default (GTK_STOCK_REFRESH) ); - gtk_icon_factory_add (factory, "pspp-stock-select", + gtk_icon_factory_add (factory, "pspp-stock-select", gtk_icon_factory_lookup_default (GTK_STOCK_INDEX) ); } @@ -213,3 +231,58 @@ create_icon_factory (void) gtk_icon_factory_add_default (factory); } + + +static error_t +parse_non_options (int key, char *arg, struct argp_state *state) +{ + struct source_stream *ss = state->input; + + if ( NULL == ss ) + return 0; + + switch (key) + { + case ARGP_KEY_ARG: + { + struct string syntax; + FILE *fp = fopen (arg, "r"); + if (NULL == fp) + { + const int errnum = errno; + fprintf (state->err_stream, _("Cannot open %s: %s.\n"), + arg, strerror (errnum)); + return 0; + } + if ( sfm_detect (fp)) + { + ds_init_cstr (&syntax, "GET FILE="); + goto close; + } + rewind (fp); + if (pfm_detect (fp)) + { + ds_init_cstr (&syntax, "IMPORT FILE="); + } + close: + fclose (fp); + + syntax_gen_string (&syntax, ss_cstr (arg)); + ds_put_cstr (&syntax, "."); + + getl_append_source (ss, + create_syntax_string_source (ds_cstr (&syntax)), + GETL_BATCH, + ERRMODE_CONTINUE); + + ds_destroy (&syntax); + break; + } + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + + +const struct argp non_option_argp = {NULL, parse_non_options, 0, 0, 0, 0, 0}; diff --git a/src/ui/gui/psppire.h b/src/ui/gui/psppire.h index 9c99af02..92cd1357 100644 --- a/src/ui/gui/psppire.h +++ b/src/ui/gui/psppire.h @@ -17,8 +17,13 @@ #ifndef PSPPIRE_H #define PSPPIRE_H +#include -void initialize (void); +struct command_line_processor ; +extern const struct argp non_option_argp ; + + +void initialize (struct command_line_processor *, int argc, char **argv); void de_initialize (void); #endif /* PSPPIRE_H */ diff --git a/src/ui/source-init-opts.c b/src/ui/source-init-opts.c new file mode 100644 index 00000000..43ae5c62 --- /dev/null +++ b/src/ui/source-init-opts.c @@ -0,0 +1,136 @@ +/* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2008 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 + 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 "source-init-opts.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gettext.h" +#define _(msgid) gettext (msgid) +#define N_(msgid) msgid + +static const struct argp_option post_init_options [] = { + {"algorithm", 'a', "{compatible|enhanced}", 0, N_("set to `compatible' if you want output calculated from broken algorithms"), 0}, + {"include", 'I', "DIR", 0, N_("Append DIR to include path"), 0}, + {"no-include", 'I', 0, 0, N_("Clear include path"), 0}, + {"no-statrc", 'r', 0, 0, N_("Disable execution of .pspp/rc at startup"), 0}, + {"config-dir", 'B', "DIR", 0, N_("Set configuration directory to DIR"), 0}, + {"safer", 's', 0, 0, N_("Don't allow some unsafe operations"), 0}, + {"syntax", 'x', "{compatible|enhanced}", 0, N_("Set to `compatible' if you want only to accept SPSS compatible syntax"), 0}, + { 0, 0, 0, 0, 0, 0 } +}; + +static error_t +parse_post_init_opts (int key, char *arg, struct argp_state *state) +{ + struct source_init + { + bool process_statrc; + }; + + struct source_init *sip = state->hook; + + struct source_stream *ss = state->input; + + if ( state->input == NULL) + return 0; + + switch (key) + { + case ARGP_KEY_INIT: + state->hook = sip = xzalloc (sizeof (struct source_init)); + sip->process_statrc = true; + break; + case ARGP_KEY_FINI: + free (sip); + break; + case 'a': + if ( 0 == strcmp (arg, "compatible") ) + settings_set_algorithm (COMPATIBLE); + else if ( 0 == strcmp (arg, "enhanced")) + settings_set_algorithm (ENHANCED); + else + { + argp_failure (state, 1, 0, _("Algorithm must be either \"compatible\" or \"enhanced\".")); + } + break; + case 'B': + config_path = arg; + break; + case 'I': + if (arg == NULL || !strcmp (arg, "-")) + getl_clear_include_path (ss); + else + getl_add_include_dir (ss, arg); + break; + case 'r': + sip->process_statrc = false; + break; + case ARGP_KEY_SUCCESS: + if (sip->process_statrc) + { + char *pspprc_fn = fn_search_path ("rc", config_path); + if (pspprc_fn != NULL) + { + getl_append_source (ss, + create_syntax_file_source (pspprc_fn), + GETL_BATCH, + ERRMODE_CONTINUE + ); + + free (pspprc_fn); + } + } + break; + case 's': + settings_set_safer_mode (); + break; + case 'x': + if ( 0 == strcmp (arg, "compatible") ) + settings_set_syntax (COMPATIBLE); + else if ( 0 == strcmp (arg, "enhanced")) + settings_set_syntax (ENHANCED); + else + { + argp_failure (state, 1, 0, _("Syntax must be either \"compatible\" or \"enhanced\".")); + } + break; + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +const struct argp post_init_argp = + {post_init_options, parse_post_init_opts, 0, 0, 0, 0, 0}; + diff --git a/src/ui/terminal/command-line.h b/src/ui/source-init-opts.h similarity index 68% rename from src/ui/terminal/command-line.h rename to src/ui/source-init-opts.h index 601c73cc..87493531 100644 --- a/src/ui/terminal/command-line.h +++ b/src/ui/source-init-opts.h @@ -1,5 +1,5 @@ -/* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. +/* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2008 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 @@ -14,13 +14,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#if !INCLUDED_CMDLINE_H -#define INCLUDED_CMDLINE_H 1 -#include +#ifndef SOURCE_INIT_OPTS +#define SOURCE_INIT_OPTS -struct source_stream ; +extern const struct argp post_init_argp; -bool parse_command_line (int argc, char **argv, struct source_stream *); +#endif -#endif /* cmdline.h */ diff --git a/src/ui/terminal/automake.mk b/src/ui/terminal/automake.mk index 988f24d5..598cdddd 100644 --- a/src/ui/terminal/automake.mk +++ b/src/ui/terminal/automake.mk @@ -3,15 +3,16 @@ noinst_LTLIBRARIES += src/ui/terminal/libui.la src_ui_terminal_libui_la_SOURCES = \ - src/ui/terminal/command-line.c \ - src/ui/terminal/command-line.h \ src/ui/terminal/read-line.c \ src/ui/terminal/read-line.h \ src/ui/terminal/main.c \ src/ui/terminal/msg-ui.c \ src/ui/terminal/msg-ui.h \ src/ui/terminal/terminal.c \ - src/ui/terminal/terminal.h + src/ui/terminal/terminal.h \ + src/ui/terminal/terminal-opts.c \ + src/ui/terminal/terminal-opts.h + src_ui_terminal_libui_la_CFLAGS = -DINSTALLDIR=\"$(bindir)\" $(NCURSES_CFLAGS) diff --git a/src/ui/terminal/command-line.c b/src/ui/terminal/command-line.c deleted file mode 100644 index 95b22ceb..00000000 --- a/src/ui/terminal/command-line.c +++ /dev/null @@ -1,274 +0,0 @@ -/* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2007 Free Software Foundation, Inc. - - 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 "command-line.h" -#include "msg-ui.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "progname.h" -#include -#include -#include -#include -#include -#include -#include -#include "read-line.h" - -#include "xalloc.h" - -#include "gettext.h" -#define _(msgid) gettext (msgid) -#define N_(msgid) msgid - -static void usage (void); - -/* Parses the command line specified by ARGC and ARGV as received by - main(). Returns true if normal execution should proceed, - false if the command-line indicates that PSPP should exit. */ -bool -parse_command_line (int argc, char **argv, struct source_stream *ss) -{ - static struct option long_options[] = - { - {"algorithm", required_argument, NULL, 'a'}, - {"command", required_argument, NULL, 'c'}, - {"config-directory", required_argument, NULL, 'B'}, - {"device", required_argument, NULL, 'o'}, - {"dry-run", no_argument, NULL, 'n'}, - {"edit", no_argument, NULL, 'n'}, - {"error-file", required_argument, NULL, 'e'}, - {"help", no_argument, NULL, 'h'}, - {"include-directory", required_argument, NULL, 'I'}, - {"interactive", no_argument, NULL, 'i'}, - {"just-print", no_argument, NULL, 'n'}, - {"list", no_argument, NULL, 'l'}, - {"no-include", no_argument, NULL, 'I'}, - {"no-statrc", no_argument, NULL, 'r'}, - {"out-file", required_argument, NULL, 'f'}, - {"pipe", no_argument, NULL, 'p'}, - {"recon", no_argument, NULL, 'n'}, - {"safer", no_argument, NULL, 's'}, - {"syntax", required_argument, NULL, 'x'}, - {"testing-mode", no_argument, NULL, 'T'}, - {"verbose", no_argument, NULL, 'v'}, - {"version", no_argument, NULL, 'V'}, - {0, 0, 0, 0}, - }; - - int c, i; - - bool cleared_device_defaults = false; - bool process_statrc = true; - bool interactive_mode = false; - int syntax_files = 0; - - for (;;) - { - c = getopt_long (argc, argv, "a:x:B:c:e:f:hiI:lno:prsvV", long_options, NULL); - if (c == -1) - break; - - switch (c) - { - /* Compatibility options */ - case 'a': - if ( 0 == strcmp(optarg,"compatible") ) - settings_set_algorithm(COMPATIBLE); - else if ( 0 == strcmp(optarg,"enhanced")) - settings_set_algorithm(ENHANCED); - else - { - usage (); - return false; - } - break; - - case 'x': - if ( 0 == strcmp(optarg,"compatible") ) - settings_set_syntax (COMPATIBLE); - else if ( 0 == strcmp(optarg,"enhanced")) - settings_set_syntax (ENHANCED); - else - { - usage (); - return false; - } - break; - case 'e': - msg_ui_set_error_file (optarg); - break; - case 'B': - config_path = optarg; - break; - case 'f': - printf (_("%s is not yet implemented."), "-f"); - putchar('\n'); - break; - case 'h': - usage (); - return false; - case 'i': - interactive_mode = true; - break; - case 'I': - if (optarg == NULL || !strcmp (optarg, "-")) - getl_clear_include_path (ss); - else - getl_add_include_dir (ss, optarg); - break; - case 'l': - outp_list_classes (); - return false; - case 'n': - printf (_("%s is not yet implemented."),"-n"); - putchar('\n'); - break; - case 'o': - if (!cleared_device_defaults) - { - outp_configure_clear (); - cleared_device_defaults = true; - } - outp_configure_add (optarg); - break; - case 'p': - printf (_("%s is not yet implemented."),"-p"); - putchar('\n'); - break; - case 'r': - process_statrc = false; - break; - case 's': - settings_set_safer_mode (); - break; - case 'v': - verbose_increment_level (); - break; - case 'V': - puts (version); - puts (legal); - return false; - case 'T': - settings_set_testing_mode (true); - break; - case '?': - usage (); - return false; - case 0: - break; - default: - NOT_REACHED (); - } - } - - if (process_statrc) - { - char *pspprc_fn = fn_search_path ("rc", config_path); - if (pspprc_fn != NULL) - { - getl_append_source (ss, - create_syntax_file_source (pspprc_fn), - GETL_BATCH, - ERRMODE_CONTINUE - ); - - free (pspprc_fn); - } - } - - for (i = optind; i < argc; i++) - if (strchr (argv[i], '=')) - outp_configure_macro (argv[i]); - else - { - getl_append_source (ss, - create_syntax_file_source (argv[i]), - GETL_BATCH, - ERRMODE_CONTINUE - ); - syntax_files++; - } - - if (!syntax_files || interactive_mode) - { - getl_append_source (ss, create_readln_source (), - GETL_INTERACTIVE, - ERRMODE_CONTINUE - ); - if (!cleared_device_defaults) - outp_configure_add ("interactive"); - } - - return true; -} - -/* Message that describes PSPP command-line syntax. */ -static const char pre_syntax_message[] = -N_("PSPP, a program for statistical analysis of sample data.\n" -"\nUsage: %s [OPTION]... FILE...\n" -"\nIf a long option shows an argument as mandatory, then it is mandatory\n" -"for the equivalent short option also. Similarly for optional arguments.\n" -"\nConfiguration:\n" -" -a, --algorithm={compatible|enhanced}\n" -" set to `compatible' if you want output\n" -" calculated from broken algorithms\n" -" -B, --config-dir=DIR set configuration directory to DIR\n" -" -o, --device=DEVICE select output driver DEVICE and disable defaults\n" -"\nInput and output:\n" -" -e, --error-file=FILE send error messages to FILE (appended)\n" -" -f, --out-file=FILE send output to FILE (overwritten)\n" -" -p, --pipe read syntax from stdin, send output to stdout\n" -" -I-, --no-include clear include path\n" -" -I, --include=DIR append DIR to include path\n" -"\nLanguage modifiers:\n" -" -i, --interactive interpret syntax in interactive mode\n" -" -n, --edit just check syntax; don't actually run the code\n" -" -r, --no-statrc disable execution of .pspp/rc at startup\n" -" -s, --safer don't allow some unsafe operations\n" -" -x, --syntax={compatible|enhanced}\n" -" set to `compatible' if you want only to accept\n" -" spss compatible syntax\n" -"\nInformative output:\n" -" -h, --help print this help, then exit\n" -" -l, --list print a list of known driver classes, then exit\n" -" -V, --version show PSPP version, then exit\n" -" -v, --verbose increments verbosity level\n" -"\nNon-option arguments:\n" -" FILE syntax file to execute\n" -" KEY=VALUE overrides macros in output initialization file\n" -"\n"); - -/* Message that describes PSPP command-line syntax, continued. */ -static const char post_syntax_message[] = N_("\nReport bugs to <%s>.\n"); - -/* Writes a syntax description to stdout. */ -static void -usage (void) -{ - printf (gettext (pre_syntax_message), program_name); - outp_list_classes (); - printf (gettext (post_syntax_message), PACKAGE_BUGREPORT); -} diff --git a/src/ui/terminal/main.c b/src/ui/terminal/main.c index e91677b3..904c9a1d 100644 --- a/src/ui/terminal/main.c +++ b/src/ui/terminal/main.c @@ -47,10 +47,12 @@ #include #include #include -#include #include #include #include +#include +#include +#include #include "fatal-signal.h" #include "progname.h" @@ -73,12 +75,15 @@ static struct dataset * the_dataset = NULL; static struct lexer *the_lexer; static struct source_stream *the_source_stream ; +const char *argp_program_version = version; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; + /* Program entry point. */ int main (int argc, char **argv) { int *view_width_p, *view_length_p; - + struct command_line_processor *clp; set_program_name (argv[0]); signal (SIGABRT, bug_handler); @@ -106,37 +111,58 @@ main (int argc, char **argv) the_dataset = create_dataset (); - if (parse_command_line (argc, argv, the_source_stream)) + + + clp = command_line_processor_create (_("PSPP --- A program for statistical analysis"), + _("FILE1, FILE2 ... FILEn"), NULL); + + command_line_processor_add_options (clp, &io_argp, + _("Options affecting input and output locations:"), the_source_stream); + + command_line_processor_add_options (clp, &test_argp, + _("Diagnositic options:"), the_source_stream); + + command_line_processor_add_options (clp, &post_init_argp, + _("Options affecting syntax and behavior:"), the_source_stream); + + command_line_processor_parse (clp, argc, argv); + + msg_ui_init (the_source_stream); + + if (!settings_get_testing_mode ()) + { + outp_read_devices (); + } + else + { + outp_configure_driver_line + ( + ss_cstr ("raw-ascii:ascii:listing:width=9999 length=9999 " + "output-file=\"pspp.list\" emphasis=none " + "headers=off paginate=off squeeze=on " + "top-margin=0 bottom-margin=0")); + } + + the_lexer = lex_create (the_source_stream); + + for (;;) { - msg_ui_init (the_source_stream); - if (!settings_get_testing_mode ()) - outp_read_devices (); + int result = cmd_parse (the_lexer, the_dataset); + + if (result == CMD_EOF || result == CMD_FINISH) + break; + if (result == CMD_CASCADING_FAILURE && + !getl_is_interactive (the_source_stream)) + { + msg (SE, _("Stopping syntax file processing here to avoid " + "a cascade of dependent command failures.")); + getl_abort_noninteractive (the_source_stream); + } else - outp_configure_driver_line ( - ss_cstr ("raw-ascii:ascii:listing:width=9999 length=9999 " - "output-file=\"pspp.list\" emphasis=none " - "headers=off paginate=off squeeze=on " - "top-margin=0 bottom-margin=0")); - the_lexer = lex_create (the_source_stream); - - for (;;) - { - int result = cmd_parse (the_lexer, the_dataset); - - if (result == CMD_EOF || result == CMD_FINISH) - break; - if (result == CMD_CASCADING_FAILURE && - !getl_is_interactive (the_source_stream)) - { - msg (SE, _("Stopping syntax file processing here to avoid " - "a cascade of dependent command failures.")); - getl_abort_noninteractive (the_source_stream); - } - else - check_msg_count (the_source_stream); - } + check_msg_count (the_source_stream); } + clean_up (); return any_errors (); } diff --git a/src/ui/terminal/terminal-opts.c b/src/ui/terminal/terminal-opts.c new file mode 100644 index 00000000..d2ddc6ee --- /dev/null +++ b/src/ui/terminal/terminal-opts.c @@ -0,0 +1,198 @@ +/* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2008 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 + 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 "msg-ui.h" +#include +#include +#include +#include +#include "terminal-opts.h" +#include +#include +#include "read-line.h" + +#include "gettext.h" +#define _(msgid) gettext (msgid) +#define N_(msgid) msgid + + +static const struct argp_option test_options [] = + { + {"verbose", 'v', 0, 0, N_("Increase diagnostic verbosity level"), 0}, + {"testing-mode", 'T', 0, OPTION_HIDDEN, 0, 0}, + + { 0, 0, 0, 0, 0, 0 } + }; + +static error_t +parse_test_opts (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case 'T': + settings_set_testing_mode (true); + break; + case 'v': + verbose_increment_level (); + break; + default: + return ARGP_ERR_UNKNOWN; + } + + 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) +{ + struct source_init + { + struct llx_list file_list; + bool cleared_device_defaults; + bool interactive; + }; + + struct fn_element { + struct ll ll; + const char *fn; + }; + + struct source_init *sip = state->hook; + + struct source_stream *ss = state->input; + + struct command_line_processor *clp = get_subject (state); + + switch (key) + { + case ARGP_KEY_INIT: + state->hook = sip = xzalloc (sizeof (struct source_init)); + llx_init (&sip->file_list); + break; + case ARGP_KEY_ARG: + if (strchr (arg, '=')) + outp_configure_macro (arg); + else + { + llx_push_tail (&sip->file_list, arg, &llx_malloc_mgr); + } + 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"); + } + } + break; + case ARGP_KEY_FINI: + free (sip); + break; + case 'e': + msg_ui_set_error_file (arg); + break; + case 'i': + sip->interactive = true; + break; + case 'l': + outp_list_classes (); + break; + case 'o': + if (! sip->cleared_device_defaults) + { + outp_configure_clear (); + sip->cleared_device_defaults = true; + } + outp_configure_add (arg); + break; + default: + return ARGP_ERR_UNKNOWN; + } + + 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} + }; + + +static error_t +propagate_aux (int key, char *arg, struct argp_state *state) +{ + if ( key == ARGP_KEY_INIT) + { + int i; + for (i = 0 ; i < sizeof (children) / sizeof (children[0]) - 1 ; ++i) + state->child_inputs[i] = state->input; + } + + return ARGP_ERR_UNKNOWN; +} + +const struct argp terminal_argp = {NULL, propagate_aux, 0, 0, children, 0, 0}; + +#endif diff --git a/src/ui/terminal/terminal-opts.h b/src/ui/terminal/terminal-opts.h new file mode 100644 index 00000000..e5d032d1 --- /dev/null +++ b/src/ui/terminal/terminal-opts.h @@ -0,0 +1,27 @@ +/* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2008 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 + 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 . */ + + +#ifndef TERMINAL_OPTS +#define TERMINAL_OPTS + +extern const struct argp io_argp ; +extern const struct argp test_argp ; + +extern const struct argp terminal_argp; + +#endif + -- 2.30.2