From: John Darrington Date: Thu, 29 Jan 2009 22:37:37 +0000 (+0900) Subject: Merge branch 'savannah/perl-module' X-Git-Tag: v0.7.1~1 X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d75247c28e0dce9c21070e4ee14fdc6a2338fb77;hp=0fc5ac957f04c06ab30b990600684d41c68fe1e5;p=pspp-builds.git Merge branch 'savannah/perl-module' Conflicts: po/en_GB.po src/libpspp/automake.mk --- diff --git a/Smake b/Smake index 7905c430..1dba188b 100644 --- a/Smake +++ b/Smake @@ -10,6 +10,7 @@ GNULIB_MODULES = \ byteswap \ c-ctype \ c-strtod \ + close \ crypto/md4 \ dirname \ environ \ diff --git a/configure.ac b/configure.ac index 7a67e600..345ac46b 100644 --- a/configure.ac +++ b/configure.ac @@ -41,6 +41,10 @@ PSPP_LC_PAPER AM_CONDITIONAL(WITHCHARTS, test x"$with_libplot" != x"no") +AC_ARG_VAR([PSPP_LDFLAGS], [linker flags to be used for linking the pspp binary only]) +AC_ARG_VAR([PSPPIRE_LDFLAGS], [linker flags to be used for linking the psppire binary only]) + + AC_ARG_WITH( gui, [AS_HELP_STRING([--without-gui], [don't build the PSPPIRE gui])]) diff --git a/po/en_GB.po b/po/en_GB.po index 1927c41f..6f2af173 100644 --- a/po/en_GB.po +++ b/po/en_GB.po @@ -991,28 +991,28 @@ msgstr "" msgid "An I/O error occurred writing system file \"%s\"." msgstr "" -#: src/data/variable.c:236 +#: src/data/variable.c:240 #, c-format msgid "" "Character `%c' (in %s) may not appear as the first character in a variable " "name." msgstr "" -#: src/data/variable.c:248 +#: src/data/variable.c:252 #, c-format msgid "Character `%c' (in %s) may not appear in a variable name." msgstr "" -#: src/data/variable.c:276 +#: src/data/variable.c:280 msgid "Variable name cannot be empty string." msgstr "" -#: src/data/variable.c:282 +#: src/data/variable.c:286 #, c-format msgid "Variable name %s exceeds %d-character limit." msgstr "" -#: src/data/variable.c:290 +#: src/data/variable.c:294 #, c-format msgid "`%s' may not be used as a variable name because it is a reserved word." msgstr "" @@ -4048,32 +4048,37 @@ msgstr "" msgid "Only USE ALL is currently implemented." msgstr "" -#: src/language/utilities/include.c:90 +#: src/language/utilities/include.c:92 msgid "Expecting BATCH or INTERACTIVE after SYNTAX." msgstr "" -#: src/language/utilities/include.c:107 +#: src/language/utilities/include.c:109 msgid "Expecting YES or NO after CD." msgstr "" -#: src/language/utilities/include.c:124 +#: src/language/utilities/include.c:126 msgid "Expecting CONTINUE or STOP after ERROR." msgstr "" -#: src/language/utilities/include.c:131 +#: src/language/utilities/include.c:133 #, c-format msgid "Unexpected token: `%s'." msgstr "" -#: src/language/utilities/include.c:176 +#: src/language/utilities/include.c:178 msgid "expecting file name" msgstr "" -#: src/language/utilities/include.c:188 +#: src/language/utilities/include.c:190 #, c-format msgid "Can't find `%s' in include file search path." msgstr "" +#: src/language/utilities/include.c:198 +#, c-format +msgid "Unable to open `%s': %s." +msgstr "" + #: src/language/utilities/permissions.c:73 #, c-format msgid "Expecting %s or %s." @@ -4507,12 +4512,12 @@ msgstr "" msgid "unknown configuration parameter `%s' for HTML device driver" msgstr "" -#: src/output/journal.c:68 +#: src/output/journal.c:69 #, c-format msgid "error writing \"%s\"" msgstr "" -#: src/output/journal.c:90 +#: src/output/journal.c:94 #, c-format msgid "error creating \"%s\"" msgstr "" @@ -5817,20 +5822,20 @@ msgstr "" msgid "Paste" msgstr "" -#: src/ui/gui/psppire.c:214 +#: src/ui/gui/psppire.c:226 msgid "_Reset" msgstr "" -#: src/ui/gui/psppire.c:215 +#: src/ui/gui/psppire.c:227 msgid "_Select" msgstr "" -#: src/ui/gui/psppire.c:251 +#: src/ui/gui/psppire.c:263 #, c-format msgid "Cannot open %s: %s.\n" msgstr "" -#: src/ui/gui/psppire.c:268 +#: src/ui/gui/psppire.c:280 #, c-format msgid "%s is neither a system nor portable file" msgstr "" diff --git a/src/data/file-name.c b/src/data/file-name.c index 86c8e17e..14afd60e 100644 --- a/src/data/file-name.c +++ b/src/data/file-name.c @@ -452,3 +452,45 @@ fn_hash_identity (const struct file_identity *identity) hash ^= hsh_hash_string (identity->name); return hash; } + + + +#ifdef WINDOWS32 + +/* Apparently windoze users like to see output dumped into their home directory, + not the current directory (!) */ +const char * +default_output_path (void) +{ + static const char *home_dir = NULL; + + /* Windows NT defines HOMEDRIVE and HOMEPATH. But give preference + to HOME, because the user can change HOME. */ + if (home_dir == NULL) + { + const char *home_drive = getenv ("HOMEDRIVE"); + const char *home_path = getenv ("HOMEPATH"); + + if (home_drive != NULL && home_path != NULL) + home_dir = xasprintf ("%s%s%c", + home_drive, home_path, DIRECTORY_SEPARATOR); + else + home_dir = "c:/users/default/"; /* poor default */ + } + return home_dir; +} + +#else + +/* ... whereas the rest of the world just likes it to be + put "here" for easy access. */ +const char * +default_output_path (void) +{ + static char current_dir[] = ""; + + return current_dir; +} + +#endif + diff --git a/src/data/file-name.h b/src/data/file-name.h index b4231d2f..d34bd419 100644 --- a/src/data/file-name.h +++ b/src/data/file-name.h @@ -52,4 +52,6 @@ int fn_compare_file_identities (const struct file_identity *, const struct file_identity *); unsigned int fn_hash_identity (const struct file_identity *); +const char * default_output_path (void); + #endif /* file-name.h */ diff --git a/src/data/variable.c b/src/data/variable.c index ccbe65dc..30cf03b1 100644 --- a/src/data/variable.c +++ b/src/data/variable.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 2009 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 @@ -148,17 +148,21 @@ var_clone (const struct variable *old_var) return new_var; } -/* Create a variable to be used for internal calculations only */ +/* Create a variable to be used for internal calculations only. + The variable is assigned a unique dictionary index and a case + index of CASE_IDX. */ struct variable * var_create_internal (int case_idx) { struct variable *v = var_create ("$internal", 0); - struct vardict_info vdi; + static int counter = INT_MAX / 2; vdi.dict = NULL; - vdi.dict_index = 0; vdi.case_index = case_idx; + vdi.dict_index = counter++; + if (counter == INT_MAX) + counter = INT_MAX / 2; var_set_vardict (v, &vdi); diff --git a/src/language/command.def b/src/language/command.def index e06261f9..f87747d8 100644 --- a/src/language/command.def +++ b/src/language/command.def @@ -98,7 +98,6 @@ DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "XSAVE", cmd_xsave) DEF_CMD (S_DATA, 0, "AGGREGATE", cmd_aggregate) DEF_CMD (S_DATA, 0, "AUTORECODE", cmd_autorecode) DEF_CMD (S_DATA, F_KEEP_FINAL_TOKEN, "BEGIN DATA", cmd_begin_data) -DEF_CMD (S_DATA, 0, "CORRELATIONS", cmd_correlations) DEF_CMD (S_DATA, 0, "COUNT", cmd_count) DEF_CMD (S_DATA, 0, "CROSSTABS", cmd_crosstabs) DEF_CMD (S_DATA, 0, "DELETE VARIABLES", cmd_delete_variables) @@ -114,7 +113,6 @@ DEF_CMD (S_DATA, 0, "MEANS", cmd_means) DEF_CMD (S_DATA, 0, "MODIFY VARS", cmd_modify_vars) DEF_CMD (S_DATA, 0, "NPAR TESTS", cmd_npar_tests) DEF_CMD (S_DATA, 0, "ONEWAY", cmd_oneway) -DEF_CMD (S_DATA, 0, "PEARSON CORRELATIONS", cmd_correlations) DEF_CMD (S_DATA, 0, "RANK", cmd_rank) DEF_CMD (S_DATA, 0, "REGRESSION", cmd_regression) DEF_CMD (S_DATA, 0, "RELIABILITY", cmd_reliability) @@ -157,6 +155,7 @@ UNIMPL_CMD ("CCF", "Time series cross correlation") UNIMPL_CMD ("CLEAR TRANSFORMATIONS", "Clears transformations from active file") UNIMPL_CMD ("CLUSTER", "Hierachial clustering") UNIMPL_CMD ("CONJOINT", "Analyse full concept data") +UNIMPL_CMD ("CORRELATIONS", "Correlation coefficients") UNIMPL_CMD ("CORRESPONDENCE", "Show correspondence") UNIMPL_CMD ("COXREG", "Cox proportional hazards regression") UNIMPL_CMD ("CREATE", "Create time series data") @@ -217,6 +216,7 @@ UNIMPL_CMD ("ORTHOPLAN", "Orthogonal effects design") UNIMPL_CMD ("OVERALS", "Nonlinear canonical correlation") UNIMPL_CMD ("PACF", "Partial autocorrelation") UNIMPL_CMD ("PARTIAL CORR", "Partial correlation") +UNIMPL_CMD ("PEARSON CORRELATIONS", "Correlation coefficients") UNIMPL_CMD ("PLANCARDS", "Conjoint analysis planning") UNIMPL_CMD ("PLUM", "Estimate ordinal regression models") UNIMPL_CMD ("POINT", "Marker in keyed file") diff --git a/src/language/stats/binomial.c b/src/language/stats/binomial.c index 15d0e403..b62b4dce 100644 --- a/src/language/stats/binomial.c +++ b/src/language/stats/binomial.c @@ -112,7 +112,7 @@ do_binomial (const struct dictionary *dict, int width = var_get_width (var); if (var_is_value_missing (var, value, exclude)) - break; + continue; if ( NULL == cat1[v].value ) { @@ -158,16 +158,20 @@ binomial_execute (const struct dataset *ds, if ( bst->category1 != SYSMIS ) { + int i; union value v; v.f = bst->category1; - cat1->value = value_dup (&v, 0); + for (i = 0; i < ost->n_vars; i++) + cat1[i].value = value_dup (&v, 0); } if ( bst->category2 != SYSMIS ) { + int i; union value v; v.f = bst->category2; - cat2->value = value_dup (&v, 0); + for (i = 0; i < ost->n_vars; i++) + cat2[i].value = value_dup (&v, 0); } if (do_binomial (dataset_dict(ds), input, bst, cat1, cat2, exclude)) diff --git a/src/language/stats/crosstabs.q b/src/language/stats/crosstabs.q index 60d2faee..68d11e30 100644 --- a/src/language/stats/crosstabs.q +++ b/src/language/stats/crosstabs.q @@ -1675,7 +1675,7 @@ enum_var_values (struct table_entry **entries, int entry_cnt, int var_idx, if (mode == GENERAL) { - int width = var_get_width (v); + int width = MIN (var_get_width (v), MAX_SHORT_STRING); int i; *values = xnmalloc (entry_cnt, sizeof **values); diff --git a/src/language/stats/glm.q b/src/language/stats/glm.q index 07ee7ab5..26b90365 100644 --- a/src/language/stats/glm.q +++ b/src/language/stats/glm.q @@ -243,7 +243,7 @@ run_glm (struct casereader *input, /* Accumulate the covariance matrix. */ - covariance_matrix_accumulate (cov, c); + covariance_matrix_accumulate (cov, c, NULL, 0); n_data++; } covariance_matrix_compute (cov); diff --git a/src/language/utilities/include.c b/src/language/utilities/include.c index 8e69dab5..fe98aeb8 100644 --- a/src/language/utilities/include.c +++ b/src/language/utilities/include.c @@ -16,7 +16,9 @@ #include #include +#include #include +#include #include #include #include @@ -191,6 +193,13 @@ parse_insert (struct lexer *lexer, char **filename) } *filename = relative_filename; + if (*filename == NULL) + { + msg (SE, _("Unable to open `%s': %s."), + relative_filename, strerror (errno)); + free (relative_filename); + return CMD_FAILURE; + } return CMD_SUCCESS; } diff --git a/src/libpspp/automake.mk b/src/libpspp/automake.mk index 9eed0027..dc512bb2 100644 --- a/src/libpspp/automake.mk +++ b/src/libpspp/automake.mk @@ -75,7 +75,7 @@ src_libpspp_libpspp_la_CPPFLAGS = -I $(top_srcdir)/src/libpspp $(AM_CPPFLAGS) nodist_src_libpspp_libpspp_la_SOURCES = src/libpspp/version.c -src/libpspp/version.c: $(top_srcdir)/AUTHORS $(top_builddir)/Makefile +src/libpspp/version.c: $(top_srcdir)/AUTHORS Makefile @$(MKDIR_P) src/libpspp echo "/* -*- mode: c; buffer-read-only: t -*-" > $@ echo " Generated by src/libpspp/automake.mk --- Do not edit.">> $@ diff --git a/src/math/covariance-matrix.c b/src/math/covariance-matrix.c index 32ca9bca..e1b612af 100644 --- a/src/math/covariance-matrix.c +++ b/src/math/covariance-matrix.c @@ -64,10 +64,13 @@ struct covariance_matrix int n_pass; int missing_handling; enum mv_class missing_value; - void (*accumulate) (struct covariance_matrix *, const struct ccase *); + void (*accumulate) (struct covariance_matrix *, const struct ccase *, + const struct interaction_variable **, size_t); void (*update_moments) (struct covariance_matrix *, size_t, double); }; + + static struct hsh_table *covariance_hsh_create (size_t); static hsh_hash_func covariance_accumulator_hash; static unsigned int hash_numeric_alpha (const struct variable *, @@ -93,9 +96,13 @@ static struct covariance_accumulator *get_new_covariance_accumulator (const value *); static void covariance_accumulate_listwise (struct covariance_matrix *, - const struct ccase *); + const struct ccase *, + const struct interaction_variable **, + size_t); static void covariance_accumulate_pairwise (struct covariance_matrix *, - const struct ccase *); + const struct ccase *, + const struct interaction_variable **, + size_t); struct covariance_matrix * covariance_matrix_init (size_t n_variables, @@ -227,7 +234,7 @@ column_iterate (struct design_matrix *cov, const struct variable *v, col += i; y = -1.0 * cat_get_category_count (i, v) / ssize; tmp_val = cat_subscript_to_value (i, v); - if (compare_values_short (tmp_val, val1, v)) + if (!compare_values_short (tmp_val, val1, v)) { y += -1.0; } @@ -262,7 +269,7 @@ covariance_pass_two (struct design_matrix *cov, double mean1, double mean2, row += i; x = -1.0 * cat_get_category_count (i, v1) / ssize; tmp_val = cat_subscript_to_value (i, v1); - if (compare_values_short (tmp_val, val1, v1)) + if (!compare_values_short (tmp_val, val1, v1)) { x += 1.0; } @@ -399,23 +406,23 @@ match_nodes (const struct covariance_accumulator *c, } if (var_is_numeric (v1) && var_is_alpha (v2)) { - if (compare_values_short (val2, c->val2, v2)) + if (!compare_values_short (val2, c->val2, v2)) { return 0; } } if (var_is_alpha (v1) && var_is_numeric (v2)) { - if (compare_values_short (val1, c->val1, v1)) + if (!compare_values_short (val1, c->val1, v1)) { return 0; } } if (var_is_alpha (v1) && var_is_alpha (v2)) { - if (compare_values_short (val1, c->val1, v1)) + if (!compare_values_short (val1, c->val1, v1)) { - if (compare_values_short (val2, c->val2, v2)) + if (!compare_values_short (val2, c->val2, v2)) { return 0; } @@ -490,13 +497,13 @@ update_product (const struct variable *v1, const struct variable *v2, return 0.0; } static double -update_sum (const struct variable *var, const union value *val) +update_sum (const struct variable *var, const union value *val, double weight) { assert (var != NULL); assert (val != NULL); if (var_is_alpha (var)) { - return 1.0; + return weight; } return val->f; } @@ -525,20 +532,27 @@ get_covariance_variables (const struct covariance_matrix *cov) return cov->v_variables; } + static void update_hash_entry (struct hsh_table *c, const struct variable *v1, const struct variable *v2, - const union value *val1, const union value *val2) + const union value *val1, const union value *val2, + const struct interaction_value *i_val1, + const struct interaction_value *i_val2) { struct covariance_accumulator *ca; struct covariance_accumulator *new_entry; + double iv_f1; + double iv_f2; - + iv_f1 = interaction_value_get_nonzero_entry (i_val1); + iv_f2 = interaction_value_get_nonzero_entry (i_val2); ca = get_new_covariance_accumulator (v1, v2, val1, val2); ca->dot_product = update_product (ca->v1, ca->v2, ca->val1, ca->val2); - ca->sum1 = update_sum (ca->v1, ca->val1); - ca->sum2 = update_sum (ca->v2, ca->val2); + ca->dot_product *= iv_f1 * iv_f2; + ca->sum1 = update_sum (ca->v1, ca->val1, iv_f1); + ca->sum2 = update_sum (ca->v2, ca->val2, iv_f2); ca->ssize = 1.0; new_entry = hsh_insert (c, ca); if (new_entry != NULL) @@ -568,13 +582,17 @@ update_hash_entry (struct hsh_table *c, */ static void covariance_accumulate_pairwise (struct covariance_matrix *cov, - const struct ccase *ccase) + const struct ccase *ccase, + const struct interaction_variable **i_var, + size_t n_intr) { size_t i; size_t j; const union value *val1; const union value *val2; const struct variable **v_variables; + struct interaction_value *i_val1 = NULL; + struct interaction_value *i_val2 = NULL; assert (cov != NULL); assert (ccase != NULL); @@ -584,24 +602,40 @@ covariance_accumulate_pairwise (struct covariance_matrix *cov, for (i = 0; i < cov->n_variables; ++i) { - val1 = case_data (ccase, v_variables[i]); + if (is_interaction (v_variables[i], i_var, n_intr)) + { + i_val1 = interaction_case_data (ccase, v_variables[i], i_var, n_intr); + val1 = interaction_value_get (i_val1); + } + else + { + val1 = case_data (ccase, v_variables[i]); + } if (!var_is_value_missing (v_variables[i], val1, cov->missing_value)) { cat_value_update (v_variables[i], val1); - if (var_is_alpha (v_variables[i])) + if (var_is_numeric (v_variables[i])) cov->update_moments (cov, i, val1->f); for (j = i; j < cov->n_variables; j++) { - val2 = case_data (ccase, v_variables[j]); + if (is_interaction (v_variables[j], i_var, n_intr)) + { + i_val2 = interaction_case_data (ccase, v_variables[j], i_var, n_intr); + val2 = interaction_value_get (i_val2); + } + else + { + val2 = case_data (ccase, v_variables[j]); + } if (!var_is_value_missing (v_variables[j], val2, cov->missing_value)) { update_hash_entry (cov->ca, v_variables[i], v_variables[j], - val1, val2); + val1, val2, i_val1, i_val2); if (j != i) update_hash_entry (cov->ca, v_variables[j], - v_variables[i], val2, val1); + v_variables[i], val2, val1, i_val2, i_val1); } } } @@ -625,13 +659,17 @@ covariance_accumulate_pairwise (struct covariance_matrix *cov, */ static void covariance_accumulate_listwise (struct covariance_matrix *cov, - const struct ccase *ccase) + const struct ccase *ccase, + const struct interaction_variable **i_var, + size_t n_intr) { size_t i; size_t j; const union value *val1; const union value *val2; const struct variable **v_variables; + struct interaction_value *i_val1 = NULL; + struct interaction_value *i_val2 = NULL; assert (cov != NULL); assert (ccase != NULL); @@ -641,19 +679,35 @@ covariance_accumulate_listwise (struct covariance_matrix *cov, for (i = 0; i < cov->n_variables; ++i) { - val1 = case_data (ccase, v_variables[i]); + if (is_interaction (v_variables[i], i_var, n_intr)) + { + i_val1 = interaction_case_data (ccase, v_variables[i], i_var, n_intr); + val1 = interaction_value_get (i_val1); + } + else + { + val1 = case_data (ccase, v_variables[i]); + } cat_value_update (v_variables[i], val1); - if (var_is_alpha (v_variables[i])) + if (var_is_numeric (v_variables[i])) cov->update_moments (cov, i, val1->f); for (j = i; j < cov->n_variables; j++) { - val2 = case_data (ccase, v_variables[j]); + if (is_interaction (v_variables[j], i_var, n_intr)) + { + i_val2 = interaction_case_data (ccase, v_variables[j], i_var, n_intr); + val2 = interaction_value_get (i_val2); + } + else + { + val2 = case_data (ccase, v_variables[j]); + } update_hash_entry (cov->ca, v_variables[i], v_variables[j], - val1, val2); + val1, val2, i_val1, i_val2); if (j != i) update_hash_entry (cov->ca, v_variables[j], v_variables[i], - val2, val1); + val2, val1, i_val2, i_val1); } } } @@ -662,13 +716,13 @@ covariance_accumulate_listwise (struct covariance_matrix *cov, Call this function during the data pass. Each case will be added to a hash containing all values of the covariance matrix. After the data have been passed, call covariance_matrix_compute to put the - values in the struct covariance_matrix. + values in the struct covariance_matrix. */ void covariance_matrix_accumulate (struct covariance_matrix *cov, - const struct ccase *ccase) + const struct ccase *ccase, void **aux, size_t n_intr) { - cov->accumulate (cov, ccase); + cov->accumulate (cov, ccase, (const struct interaction_variable **) aux, n_intr); } static void @@ -689,7 +743,7 @@ covariance_matrix_insert (struct design_matrix *cov, { i = 0; tmp_val = cat_subscript_to_value (i, v1); - while (!compare_values_short (tmp_val, val1, v1)) + while (compare_values_short (tmp_val, val1, v1)) { i++; tmp_val = cat_subscript_to_value (i, v1); @@ -704,7 +758,7 @@ covariance_matrix_insert (struct design_matrix *cov, col = design_matrix_var_to_column (cov, v2); i = 0; tmp_val = cat_subscript_to_value (i, v1); - while (!compare_values_short (tmp_val, val1, v1)) + while (compare_values_short (tmp_val, val1, v1)) { i++; tmp_val = cat_subscript_to_value (i, v1); diff --git a/src/math/covariance-matrix.h b/src/math/covariance-matrix.h index 33a5d750..b692e7e8 100644 --- a/src/math/covariance-matrix.h +++ b/src/math/covariance-matrix.h @@ -22,6 +22,7 @@ #define COVARIANCE_MATRIX_H #include +#include struct moments1; struct ccase; @@ -53,6 +54,6 @@ struct covariance_matrix *covariance_matrix_init (size_t, int, int, enum mv_class); void covariance_matrix_free (struct covariance_matrix *); void covariance_matrix_accumulate (struct covariance_matrix *, - const struct ccase *); + const struct ccase *, void **, size_t); struct design_matrix *covariance_to_design (const struct covariance_matrix *); #endif diff --git a/src/math/interaction.c b/src/math/interaction.c index c8ead429..33da8423 100644 --- a/src/math/interaction.c +++ b/src/math/interaction.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2009 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 @@ -24,80 +24,258 @@ OBS_VALS member. If there are K categorical variables, each with N_1, N_2, ..., N_K categories, then the interaction will have N_1 * N_2 * N_3 *...* N_K - 1 entries. + + When using these functions, make sure the orders of variables and + values match when appropriate. */ #include #include #include #include -#include +#include #include -#include "interaction.h" +#include +#include +#include -#include "xalloc.h" +struct interaction_variable +{ + int n_vars; + const struct variable **members; + struct variable *intr; + size_t n_alpha; +}; + +struct interaction_value +{ + const struct interaction_variable *intr; + union value *val; /* Concatenation of the string values in this + interaction's value, or the product of a bunch + of numeric values for a purely numeric + interaction. + */ + double f; /* Product of the numerical values in this interaction's value. */ +}; /* - Convert a list of values to a binary vector. The order of VALS must - correspond to the order of V. + An interaction_variable has type alpha if any of members have type + alpha. Otherwise, its type is numeric. */ -gsl_vector * -get_interaction (union value **vals, const struct variable **v, size_t n_vars) +struct interaction_variable * +interaction_variable_create (const struct variable **vars, int n_vars) { - gsl_vector *result = NULL; - size_t *subs = NULL; - size_t length = 1; + struct interaction_variable *result = NULL; size_t i; - size_t j; - double tmp = 1.0; - assert (n_vars > 0); - for (i = 0; i < n_vars; i++) + if (n_vars > 0) { - if (var_is_alpha (v[i])) + result = xmalloc (sizeof (*result)); + result->n_alpha = 0; + result->members = xnmalloc (n_vars, sizeof (*result->members)); + result->intr = var_create_internal (0); + result->n_vars = n_vars; + for (i = 0; i < n_vars; i++) { - length *= cat_get_n_categories (v[i]); + result->members[i] = vars[i]; + if (var_is_alpha (vars[i])) + { + result->n_alpha++; + } } - else + } + /* + VAR_SET_WIDTH sets the type of the variable. + */ + var_set_width (result->intr, MAX_SHORT_STRING * result->n_alpha + 1); + + return result; +} +void interaction_variable_destroy (struct interaction_variable *iv) +{ + var_destroy (iv->intr); + free (iv->members); + free (iv); +} + +/* + Get one of the member variables. + */ +const struct variable * +interaction_variable_get_member (const struct interaction_variable *iv, size_t i) +{ + return iv->members[i]; +} + +size_t +interaction_get_n_vars (const struct interaction_variable *iv) +{ + return (iv == NULL) ? 0 : iv->n_vars; +} + +size_t +interaction_get_n_alpha (const struct interaction_variable *iv) +{ + return iv->n_alpha; +} + +size_t +interaction_get_n_numeric (const struct interaction_variable *iv) +{ + return (interaction_get_n_vars (iv) - interaction_get_n_alpha (iv)); +} + +/* + Get the interaction varibale itself. + */ +const struct variable * +interaction_variable_get_var (const struct interaction_variable *iv) +{ + return iv->intr; +} +/* + Given list of values, compute the value of the corresponding + interaction. This "value" is not stored as the typical vector of + 0's and one double, but rather the string values are concatenated to + make one big string value, and the numerical values are multiplied + together to give the non-zero entry of the corresponding vector. + */ +struct interaction_value * +interaction_value_create (const struct interaction_variable *var, const union value **vals) +{ + struct interaction_value *result = NULL; + const struct variable *member; + size_t i; + size_t n_vars; + + if (var != NULL) + { + result = xmalloc (sizeof (*result)); + result->intr = var; + n_vars = interaction_get_n_vars (var); + result->val = value_create (n_vars * MAX_SHORT_STRING + 1); + result->f = 1.0; + for (i = 0; i < n_vars; i++) + { + member = interaction_variable_get_member (var, i); + + if (var_is_value_missing (member, vals[i], MV_ANY)) + { + value_set_missing (result->val, MAX_SHORT_STRING); + result->f = SYSMIS; + break; + } + else + { + if (var_is_alpha (var->members[i])) + { + strncat (result->val->s, vals[i]->s, MAX_SHORT_STRING); + } + else if (var_is_numeric (var->members[i])) + { + result->f *= vals[i]->f; + } + } + } + if (interaction_get_n_alpha (var) == 0) { - length = (length > 0) ? length : 1; + /* + If there are no categorical variables, then the + interaction consists of only numeric data. In this case, + code that uses this interaction_value will see the union + member as the numeric value. If we were to store that + numeric value in result->f as well, the calling code may + inadvertently square this value by multiplying by + result->val->f. Such multiplication would be correct for an + interaction consisting of both categorical and numeric + data, but a mistake for purely numerical interactions. To + avoid the error, we set result->f to 1.0 for numeric + interactions. + */ + result->val->f = result->f; + result->f = 1.0; } } - if (length > 0) + return result; +} + +union value * +interaction_value_get (const struct interaction_value *val) +{ + return val->val; +} + +/* + Returns the numeric value of the non-zero entry for the vector + corresponding to this interaction. Do not use this function to get + the numeric value of a purley numeric interaction. Instead, use the + union value * returned by interaction_value_get. + */ +double +interaction_value_get_nonzero_entry (const struct interaction_value *val) +{ + if (val != NULL) + return val->f; + return 1.0; +} + +void +interaction_value_destroy (struct interaction_value *val) +{ + if (val != NULL) { - length--; + free (val->val); + free (val); } +} - result = gsl_vector_calloc (length); - subs = xnmalloc (n_vars, sizeof (*subs)); - for (j = 0; j < n_vars; j++) +/* + Return a value from a variable that is an interaction. + */ +struct interaction_value * +interaction_case_data (const struct ccase *ccase, const struct variable *var, + const struct interaction_variable **intr_vars, size_t n_intr) +{ + size_t i; + size_t n_vars; + const struct interaction_variable *iv; + const struct variable *intr; + const struct variable *member; + const union value **vals = NULL; + + for (i = 0; i < n_intr; i++) { - if (var_is_alpha (v[j])) + iv = intr_vars[i]; + intr = interaction_variable_get_var (iv); + if (var_get_dict_index (intr) == var_get_dict_index (var)) { - subs[j] = cat_value_find (v[j], vals[j]); + break; } } - j = subs[0]; - for (i = 1; i < n_vars; i++) + n_vars = interaction_get_n_vars (iv); + vals = xnmalloc (n_vars, sizeof (*vals)); + for (i = 0; i < n_vars; i++) { - j = j * cat_get_n_categories (v[i]) + subs[i]; + member = interaction_variable_get_member (iv, i); + vals[i] = case_data (ccase, member); } - gsl_vector_set (result, j, 1.0); - /* - If any of the variables are numeric, the interaction of that - variable with another is just a scalar product. - */ - for (i = 1; i < n_vars; i++) + return interaction_value_create (iv, vals); +} + +bool +is_interaction (const struct variable *var, const struct interaction_variable **iv, size_t n_intr) +{ + size_t i; + const struct variable *intr; + + for (i = 0; i < n_intr; i++) { - if (var_is_numeric (v[i])) + intr = interaction_variable_get_var (iv[i]); + if (var_get_dict_index (intr) == var_get_dict_index (var)) { - tmp *= vals[i]->f; + return true; } } - if (fabs (tmp - 1.0) > GSL_DBL_EPSILON) - { - gsl_vector_set (result, j, tmp); - } - free (subs); - - return result; + return false; } + diff --git a/src/math/interaction.h b/src/math/interaction.h index 07006078..73b440be 100644 --- a/src/math/interaction.h +++ b/src/math/interaction.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2009 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 @@ -14,5 +14,28 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -gsl_vector * -get_interaction (union value **, const struct variable **, size_t); +#ifndef INTERACTION_H +#define INTERACTION_H +#include + +struct interaction_variable; +struct interaction_value; + +struct interaction_variable * interaction_variable_create (const struct variable **, int); +void interaction_variable_destroy (struct interaction_variable *); +struct interaction_value * interaction_value_create (const struct interaction_variable *, const union value **); +void interaction_value_destroy (struct interaction_value *); +size_t interaction_variable_get_n_vars (const struct interaction_variable *); +double interaction_value_get_nonzero_entry (const struct interaction_value *); +union value * interaction_value_get (const struct interaction_value *); +const struct variable * interaction_variable_get_var (const struct interaction_variable *); +size_t interaction_get_n_numeric (const struct interaction_variable *); +size_t interaction_get_n_alpha (const struct interaction_variable *); +size_t interaction_get_n_vars (const struct interaction_variable *); +const struct variable * interaction_variable_get_member (const struct interaction_variable *, size_t); +bool is_interaction (const struct variable *, const struct interaction_variable **, size_t); +struct interaction_value * +interaction_case_data (const struct ccase *, const struct variable *, + const struct interaction_variable **, size_t); +double interaction_value_get_nonzero_entry (const struct interaction_value *); +#endif diff --git a/src/output/journal.c b/src/output/journal.c index ef50285e..67657f62 100644 --- a/src/output/journal.c +++ b/src/output/journal.c @@ -22,6 +22,7 @@ #include #include +#include #include #include "fwriteerror.h" @@ -83,7 +84,10 @@ journal_write (bool prefix, const char *line) if (journal_file == NULL) { if (journal_file_name == NULL) - journal_file_name = xstrdup ("pspp.jnl"); + { + const char *output_path = default_output_path (); + journal_file_name = xasprintf ("%s%s", output_path, "pspp.jnl"); + } journal_file = fopen (journal_file_name, "w"); if (journal_file == NULL) { diff --git a/src/ui/gui/automake.mk b/src/ui/gui/automake.mk index af880fc3..2183e4e8 100644 --- a/src/ui/gui/automake.mk +++ b/src/ui/gui/automake.mk @@ -9,6 +9,7 @@ src_ui_gui_psppire_CFLAGS = $(GTK_CFLAGS) $(GLADE_CFLAGS) -Wall \ src_ui_gui_psppire_LDFLAGS = \ + $(PSPPIRE_LDFLAGS) \ $(PG_LDFLAGS) diff --git a/src/ui/gui/output-viewer.c b/src/ui/gui/output-viewer.c index bf647e90..2b0c4af8 100644 --- a/src/ui/gui/output-viewer.c +++ b/src/ui/gui/output-viewer.c @@ -16,6 +16,7 @@ #include #include +#include #include "window-manager.h" #include "output-viewer.h" #include "helper.h" @@ -62,7 +63,7 @@ on_delete (GtkWidget *w, GdkEvent *event, gpointer user_data) the_output_viewer = NULL; - unlink (OUTPUT_FILE_NAME); + unlink (output_file_name ()); return FALSE; } @@ -181,7 +182,7 @@ reload_the_viewer (void) struct stat buf; /* If there is no output, then don't do anything */ - if (0 != stat (OUTPUT_FILE_NAME, &buf)) + if (0 != stat (output_file_name (), &buf)) return ; if ( NULL == the_output_viewer ) @@ -193,6 +194,7 @@ reload_the_viewer (void) reload_viewer (the_output_viewer); } +#define OUTPUT_FILE_NAME "psppire.txt" void reload_viewer (struct output_viewer *ov) @@ -248,10 +250,10 @@ reload_viewer (struct output_viewer *ov) { if ( ov->fp == NULL) { - ov->fp = fopen (OUTPUT_FILE_NAME, "r"); + ov->fp = fopen (output_file_name (), "r"); if ( ov->fp == NULL) { - g_print ("Cannot open %s\n", OUTPUT_FILE_NAME); + g_print ("Cannot open %s\n", output_file_name ()); return; } } @@ -277,3 +279,16 @@ reload_viewer (struct output_viewer *ov) + +const char * +output_file_name (void) +{ + const char *dir = default_output_path (); + static char *filename = NULL; + + if ( NULL == filename ) + filename = xasprintf ("%s%s", dir, OUTPUT_FILE_NAME); + + + return filename; +} diff --git a/src/ui/gui/output-viewer.h b/src/ui/gui/output-viewer.h index b5c9ffce..e5bf5c1c 100644 --- a/src/ui/gui/output-viewer.h +++ b/src/ui/gui/output-viewer.h @@ -33,7 +33,6 @@ void reload_viewer (struct output_viewer *); void reload_the_viewer (void); -#define OUTPUT_FILE_NAME "psppire.txt" - +const char * output_file_name (void); #endif diff --git a/src/ui/gui/psppire.c b/src/ui/gui/psppire.c index 02415d68..2918238c 100644 --- a/src/ui/gui/psppire.c +++ b/src/ui/gui/psppire.c @@ -121,13 +121,25 @@ initialize (struct command_line_processor *clp, int argc, char **argv) create_icon_factory (); - outp_configure_driver_line ( - ss_cstr ("gui:ascii:screen:squeeze=on headers=off top-margin=0 " - "bottom-margin=0 paginate=off length=auto width=auto " - "emphasis=none " - "output-file=\"" OUTPUT_FILE_NAME "\" append=yes")); + { + const char *filename = output_file_name (); + + struct string config_string; + + ds_init_empty (&config_string); + + ds_put_format (&config_string, + "gui:ascii:screen:squeeze=on headers=off top-margin=0 " + "bottom-margin=0 paginate=off length=auto width=auto " + "emphasis=none " + "output-file=\"%s\" append=yes", filename); - unlink (OUTPUT_FILE_NAME); + outp_configure_driver_line (ds_ss (&config_string)); + + unlink (filename); + + ds_destroy (&config_string); + } journal_enable (); textdomain (PACKAGE); diff --git a/src/ui/terminal/automake.mk b/src/ui/terminal/automake.mk index 598cdddd..5ab09857 100644 --- a/src/ui/terminal/automake.mk +++ b/src/ui/terminal/automake.mk @@ -30,7 +30,7 @@ src_ui_terminal_pspp_LDADD = \ @LIBINTL@ @LIBREADLINE@ -src_ui_terminal_pspp_LDFLAGS = $(PG_LDFLAGS) +src_ui_terminal_pspp_LDFLAGS = $(PSPP_LDFLAGS) $(PG_LDFLAGS) if RELOCATABLE_VIA_LD src_ui_terminal_pspp_LDFLAGS += `$(RELOCATABLE_LDFLAGS) $(bindir)` diff --git a/tests/command/insert.sh b/tests/command/insert.sh index be7f9e08..f80dc5fc 100755 --- a/tests/command/insert.sh +++ b/tests/command/insert.sh @@ -252,4 +252,23 @@ $TEMPDIR/foo.sps:10: error: DISPLAY: AKSDJ is not a variable name. EOF if [ $? -ne 0 ] ; then fail ; fi +# Test for regression against bug #24569 in which PSPP crashed +# upon attempt to insert a nonexistent file. +activity="create wrapper 9" +cat < $TESTFILE +INSERT + FILE='$TEMPDIR/nonexistent' + ERROR=CONTINUE. + . + +LIST. + +EOF +if [ $? -ne 0 ] ; then no_result ; fi + +#This command should fail +activity="run program 7" +$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE > /dev/null +if [ $? -eq 0 ] ; then no_result ; fi + pass;