Merge commit 'HEAD'; commit 'savannah/master'
authorJohn Darrington <john@darrington.wattle.id.au>
Fri, 20 Feb 2009 01:22:49 +0000 (10:22 +0900)
committerJohn Darrington <john@darrington.wattle.id.au>
Fri, 20 Feb 2009 01:22:49 +0000 (10:22 +0900)
Conflicts:

src/ui/gui/crosstabs-dialog.c
src/ui/gui/goto-case-dialog.c
src/ui/gui/helper.c
src/ui/gui/output-viewer.c
src/ui/gui/output-viewer.h
src/ui/gui/psppire.c
src/ui/gui/regression-dialog.c

178 files changed:
AUTHORS
INSTALL
Makefile.am
NEWS
Smake
configure.ac
lib/automake.mk
lib/misc/README [deleted file]
lib/misc/automake.mk [deleted file]
lib/misc/wx-mp-sr.c [deleted file]
lib/misc/wx-mp-sr.h [deleted file]
perl-module/COPYING [new file with mode: 0644]
perl-module/Changes [new file with mode: 0644]
perl-module/Examples.pod [new file with mode: 0644]
perl-module/MANIFEST [new file with mode: 0644]
perl-module/Makefile.PL [new file with mode: 0644]
perl-module/PSPP.bs [new file with mode: 0644]
perl-module/PSPP.xs [new file with mode: 0644]
perl-module/README [new file with mode: 0644]
perl-module/automake.mk [new file with mode: 0644]
perl-module/lib/PSPP.pm [new file with mode: 0644]
perl-module/ppport.h [new file with mode: 0644]
perl-module/t/Pspp.t [new file with mode: 0644]
perl-module/typemap [new file with mode: 0644]
po/en_GB.po
src/data/case-map.c
src/data/case-map.h
src/data/case-matcher.c
src/data/case-matcher.h
src/data/case-tmpfile.c
src/data/case-tmpfile.h
src/data/case.c
src/data/case.h
src/data/casegrouper.c
src/data/caseinit.c
src/data/casereader-filter.c
src/data/casereader-provider.h
src/data/casereader-translator.c
src/data/casereader.c
src/data/casereader.h
src/data/casewindow.c
src/data/casewindow.h
src/data/casewriter-provider.h
src/data/casewriter-translator.c
src/data/casewriter.c
src/data/casewriter.h
src/data/datasheet.c
src/data/datasheet.h
src/data/file-name.c
src/data/file-name.h
src/data/gnumeric-reader.c
src/data/lazy-casereader.c
src/data/por-file-reader.c
src/data/por-file-reader.h
src/data/por-file-writer.c
src/data/por-file-writer.h
src/data/procedure.c
src/data/procedure.h
src/data/psql-reader.c
src/data/scratch-reader.h
src/data/scratch-writer.c
src/data/scratch-writer.h
src/data/sparse-cases.c
src/data/subcase.c
src/data/sys-file-reader.c
src/data/sys-file-reader.h
src/data/sys-file-writer.c
src/data/sys-file-writer.h
src/data/transformations.c
src/data/transformations.h
src/data/variable.c
src/language/automake.mk
src/language/command.def
src/language/control/do-if.c
src/language/control/loop.c
src/language/data-io/combine-files.c
src/language/data-io/data-list.c
src/language/data-io/data-parser.c
src/language/data-io/inpt-pgm.c
src/language/data-io/list.q
src/language/data-io/print-space.c
src/language/data-io/print.c
src/language/data-io/save.c
src/language/expressions/evaluate.c
src/language/expressions/operations.def
src/language/lexer/lexer.c
src/language/stats/aggregate.c
src/language/stats/autorecode.c
src/language/stats/binomial.c
src/language/stats/chisquare.c
src/language/stats/crosstabs.q
src/language/stats/descriptives.c
src/language/stats/examine.q
src/language/stats/flip.c
src/language/stats/frequencies.q
src/language/stats/glm.q
src/language/stats/npar-summary.c
src/language/stats/oneway.q
src/language/stats/rank.q
src/language/stats/regression.q
src/language/stats/reliability.q
src/language/stats/t-test.q
src/language/stats/wilcoxon.c
src/language/tests/datasheet-check.c
src/language/tests/datasheet-check.h
src/language/utilities/include.c
src/language/xforms/compute.c
src/language/xforms/count.c
src/language/xforms/fail.c
src/language/xforms/recode.c
src/language/xforms/sample.c
src/language/xforms/select-if.c
src/libpspp/automake.mk
src/libpspp/message.c
src/libpspp/str.c
src/math/automake.mk
src/math/covariance-matrix.c
src/math/covariance-matrix.h
src/math/interaction.c
src/math/interaction.h
src/math/levene.c
src/math/merge.c
src/math/np.c
src/math/order-stats.c
src/math/sort.c
src/math/wilcoxon-sig.c [new file with mode: 0644]
src/math/wilcoxon-sig.h [new file with mode: 0644]
src/output/journal.c
src/ui/gui/.gitignore
src/ui/gui/about.c
src/ui/gui/automake.mk
src/ui/gui/comments-dialog.c
src/ui/gui/compute-dialog.c
src/ui/gui/compute-dialog.h
src/ui/gui/crosstabs-dialog.c
src/ui/gui/crosstabs-dialog.h
src/ui/gui/examine-dialog.c
src/ui/gui/examine-dialog.h
src/ui/gui/find-dialog.c
src/ui/gui/frequencies-dialog.c
src/ui/gui/frequencies-dialog.h
src/ui/gui/goto-case-dialog.c
src/ui/gui/goto-case-dialog.h
src/ui/gui/helper.c
src/ui/gui/helper.h
src/ui/gui/message-dialog.c
src/ui/gui/oneway-anova-dialog.c
src/ui/gui/psppire-data-editor.c
src/ui/gui/psppire-data-store.c
src/ui/gui/psppire-data-store.h
src/ui/gui/psppire-dialog.c
src/ui/gui/psppire.c
src/ui/gui/psppire.glade
src/ui/gui/rank-dialog.c
src/ui/gui/rank-dialog.h
src/ui/gui/recode-dialog.c
src/ui/gui/regression-dialog.c
src/ui/gui/regression-dialog.h
src/ui/gui/select-cases-dialog.c
src/ui/gui/select-cases-dialog.h
src/ui/gui/sort-cases-dialog.c
src/ui/gui/sort-cases-dialog.h
src/ui/gui/split-file-dialog.c
src/ui/gui/t-test-independent-samples-dialog.c
src/ui/gui/t-test-one-sample.c
src/ui/gui/t-test-options.c
src/ui/gui/t-test-options.h
src/ui/gui/t-test-paired-samples.c
src/ui/gui/transpose-dialog.c
src/ui/gui/variable-info-dialog.c
src/ui/gui/variable-info-dialog.h
src/ui/gui/weight-cases-dialog.c
src/ui/terminal/automake.mk
src/ui/terminal/main.c
tests/automake.mk
tests/bugs/examine-missing2.sh
tests/command/insert.sh
tests/command/line-ends.sh [new file with mode: 0755]

diff --git a/AUTHORS b/AUTHORS
index 43103dcd8fc7f3560560a29a97971699d176f2db..af7e9075f8da674b0013c55ec974b998ff9db0e8 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -14,10 +14,6 @@ to other modules.
 including lib/gslextras and the linear regression features. Jason 
 is also an important contributor to GSL, which is used by PSPP. 
 
-* Rob van Son wrote the routine for calculation of the significance
-of the Wilcoxon matched pairs signed rank statistic used by the
- NPAR TEST command.
-
 
 We also thank past contributors:
 
@@ -26,3 +22,8 @@ We also thank past contributors:
 * Michael Kiefte contributed bug fixes and other enhancements.
 
 * Patrick Kobly contributed bug fixes and other enhancements.
+
+* Rob van Son wrote the original version of the routine for
+  calculation of the significance of the Wilcoxon matched pairs signed
+  rank statistic used by the NPAR TEST command.
+
diff --git a/INSTALL b/INSTALL
index e687c55114b6d45690a3a48965225dcf92a6bbb7..9254a0d36f707dc313f7fe2dc9c9ebfc2abc1213 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -152,8 +152,9 @@ release.
 
   4. Type `make install' to install the programs and any data files
      and documentation.  Ordinarily you will need root permissions to
-     do this; if you cannot get root permissions, see "Installation
-     Names", below.
+     do this.  The "su" and "sudo" commands are common ways to obtain
+     root permissions.  If you cannot get root permissions, see
+     "Installation Names", below.
 
   5. You can remove the program binaries and object files from the
      source code directory by typing `make clean'.  To also remove the
@@ -236,7 +237,12 @@ Optional Features
    of libraries are detected.   Use of this option is not recommended.
    If you use it, some features may be missing and the build may fail
    with obscure error messages.
-   
+
+`--enable-relocatable'
+   This option is useful for building a package which can be installed
+   into an arbitrary directory and freely copied to any other directory.
+   If you use this option, you will probably want to install the pspp
+   with a command similar to "make install DESTDIR=<distination>".
 
 Defining Variables
 ==================
index 23305294af2176bedbc9b08ed4256e6f9aa5a308..06ae2e00973749d9ef17a094bb88662c37906634 100644 (file)
@@ -60,6 +60,10 @@ if WITH_GUI_TOOLS
 include $(top_srcdir)/glade/automake.mk
 endif
 
+if WITH_PERL_MODULE
+include $(top_srcdir)/perl-module/automake.mk
+endif
+
 PHONY += $(DIST_HOOKS)
 dist-hook: $(DIST_HOOKS)
 .PHONY: $(PHONY)
diff --git a/NEWS b/NEWS
index 1070638b4e641a102031b3df2946015ca7966847..a83f83102ef3c29c5d04f1e9651bbcbf9fca9a66 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,10 +1,19 @@
 PSPP NEWS -- history of user-visible changes.
-Time-stamp: <2008-10-11 10:04:51 blp>
-Copyright (C) 1996-9, 2000, 2008 Free Software Foundation, Inc.
+Time-stamp: <2009-02-05 20:31:51 blp>
+Copyright (C) 1996-9, 2000, 2008, 2009 Free Software Foundation, Inc.
 See the end for copying conditions.
 
 Please send PSPP bug reports to bug-gnu-pspp@gnu.org.
 
+Changes from 0.7.1 to 0.7.2:
+
+ * Updated Perl module interface.
+
+Changes from 0.7.0 to 0.7.1:
+
+ *  Added a perl module to facilitate reading and writing of pspp system 
+    files from perl programs.
+
 Changes from 0.6.1 to 0.7.0:
 
   * Custom variable and data file attributes are now supported.
diff --git a/Smake b/Smake
index 7905c430fe28401c4e5f454a0e4c3218d3a8f283..1dba188b271422372c213d48b3b4126e7988963f 100644 (file)
--- a/Smake
+++ b/Smake
@@ -10,6 +10,7 @@ GNULIB_MODULES = \
        byteswap \
        c-ctype \
        c-strtod \
+       close \
        crypto/md4 \
        dirname \
        environ \
index 1abc80430659c53a3d972d03c9b5261081a90b08..fc4b9828e9a4d2fa286eb5db9a8f4d77836d7b07 100644 (file)
@@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script.
 
 dnl Initialize.
 AC_PREREQ(2.60)
-AC_INIT([pspp],[0.7.0],[bug-gnu-pspp@gnu.org])
+AC_INIT([pspp],[0.7.2],[bug-gnu-pspp@gnu.org])
 AC_CONFIG_HEADERS([config.h])
 AM_INIT_AUTOMAKE
 
@@ -41,14 +41,15 @@ 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])])
 
 required_gtk_version=2.12
-if test x"$enable_anachronistic_dependencies" = x"yes"  ; then
-  required_gtk_version=2.8.20
-fi
 
 if test x"$with_gui" != x"no" ; then 
   PKG_CHECK_MODULES(GTK, gtk+-2.0 >= $required_gtk_version,,
@@ -128,6 +129,8 @@ if test x"$with_gui_tools" = x"yes" ; then
 fi
 AM_CONDITIONAL(WITH_GUI_TOOLS, test x"$with_gui_tools" = x"yes")
 
+AM_CONDITIONAL(WITH_PERL_MODULE, test x"$cross_compiling" != x"yes")
+
 AC_SEARCH_LIBS([cblas_dsdot], [gslcblas],,[PSPP_REQUIRED_PREREQ([libgslcblas])])
 AC_SEARCH_LIBS([gsl_cdf_binomial_P], [gsl],,[PSPP_REQUIRED_PREREQ([libgsl (version 1.8 or later)])])
 PSPP_GSL_NEEDS_FGNU89_INLINE
index 7cd9c9f477da0fd0b76359225d88dbc0f4edec62..6b20c67478909fe6232730b58d7b4056de720490 100644 (file)
@@ -1,7 +1,6 @@
 ## Process this file with automake to produce Makefile.in  -*- makefile -*-
 
 include $(top_srcdir)/lib/linreg/automake.mk
-include $(top_srcdir)/lib/misc/automake.mk
 
 if WITHGUI
 include $(top_srcdir)/lib/gtk-contrib/automake.mk
diff --git a/lib/misc/README b/lib/misc/README
deleted file mode 100644 (file)
index 68ba91a..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-This is not part of the GNU PSPP program, but is used with GNU PSPP.
-
diff --git a/lib/misc/automake.mk b/lib/misc/automake.mk
deleted file mode 100644 (file)
index 3b4f1a9..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-## Process this file with automake to produce Makefile.in  -*- makefile -*-
-
-noinst_LTLIBRARIES += lib/misc/libmisc.la
-
-lib_misc_libmisc_la_SOURCES = \
-       lib/misc/wx-mp-sr.c  lib/misc/wx-mp-sr.h 
-
-EXTRA_DIST += lib/misc/README
diff --git a/lib/misc/wx-mp-sr.c b/lib/misc/wx-mp-sr.c
deleted file mode 100644 (file)
index 39e83b9..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-#include <config.h>
-#include "wx-mp-sr.h"
-
-/*********************************************************************
-* 
-* Calculate the exact level of significance for a 
-* Wilcoxon Matched-Pair Signed-Ranks Test using the sample's
-* Sum of Ranks W and the sample size (i.e., number of pairs) N.
-* This whole routine can be run as a stand-alone program.
-*
-* Use: 
-* WX-MP-SR W N
-*
-* Copyright 1996, Rob van Son
-*
-* 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 2 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, write to the Free Software Foundation, Inc.,
-* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*
-* -------------------------------------------------------
-*                 Rob van Son
-* Institute of Phonetic Sciences & IFOTT 
-* University of Amsterdam, Spuistraat 210 
-* NL-1012VT Amsterdam, The Netherlands
-* Tel.: (+31) 205252196        Fax.: (+31) 205252197
-* Email: r.j.j.h.vanson@uva.nl
-* WWW page: http://www.fon.hum.uva.nl/rob
-* -------------------------------------------------------
-*
-* This is the actual routine that calculates the exact (two-tailed)
-* level of significance for the Wilcoxon Matched-Pairs Signed-Ranks
-* test. The inputs are the Sum of Ranks of either the positive of 
-* negative samples (W) and the sample size (N).
-* The Level of significance is calculated by checking for each
-* possible outcome (2**N possibilities) whether the sum of ranks
-* is larger than or equal to the observed Sum of Ranks (W).
-*
-* NOTE: The execution-time scales like ~ N*2**N, i.e., N*pow(2, N), 
-* which is more than exponential. Adding a single pair to the sample 
-* (i.e., increase N by 1) will more than double the time needed to 
-* complete the calculations (apart from an additive constant).
-* The execution-time of this program can easily outrun your 
-* patience.
-*
-***********************************************************************/ 
-
-double LevelOfSignificanceWXMPSR(double Winput, long int N)
-{
-  unsigned long int W, MaximalW, NumberOfPossibilities, CountLarger;
-  unsigned long int i, RankSum, j;
-  double p;
-
-  /* Determine Wmax, i.e., work with the largest Rank Sum */
-  MaximalW = N*(N+1)/2;
-  if(Winput < MaximalW/2)Winput = MaximalW - Winput;
-  W = Winput;    /* Convert to long int */
-  if(W != Winput)++W;  /* Increase to next full integer */
-  
-  /* The total number of possible outcomes is 2**N  */
-  NumberOfPossibilities = 1 << N;
-  
-  /* Initialize and loop. The loop-interior will be run 2**N times. */
-  CountLarger = 0;
-  /* Generate all distributions of sign over ranks as bit-patterns (i). */
-  for(i=0; i < NumberOfPossibilities; ++i)
-  { 
-    RankSum = 0;
-    /* 
-       Shift "sign" bits out of i to determine the Sum of Ranks (j). 
-    */
-    for(j=0; j < N; ++j)
-    { 
-      if((i >> j) & 1)RankSum += j + 1;  
-    };
-    /*
-    * Count the number of "samples" that have a Sum of Ranks larger than 
-    * or equal to the one found (i.e., >= W).
-    */
-    if(RankSum >= W)++CountLarger;
-  };
-  /*****************************************************************
-  * The level of significance is the number of outcomes with a
-  * sum of ranks equal to or larger than the one found (W) 
-  * divided by the total number of possible outcomes. 
-  * The level is doubled to get the two-tailed result.
-  ******************************************************************/
-  p = 2*((double)CountLarger) / ((double)NumberOfPossibilities);
-
-  return p;
-}
-
diff --git a/lib/misc/wx-mp-sr.h b/lib/misc/wx-mp-sr.h
deleted file mode 100644 (file)
index ec3ef5e..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef WX_MP_SR
-#define WX_MP_SR 1
-
-double LevelOfSignificanceWXMPSR(double Winput, long int N);
-
-#endif
diff --git a/perl-module/COPYING b/perl-module/COPYING
new file mode 100644 (file)
index 0000000..4432540
--- /dev/null
@@ -0,0 +1,676 @@
+
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                      TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+  
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                    END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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 <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+
diff --git a/perl-module/Changes b/perl-module/Changes
new file mode 100644 (file)
index 0000000..5919ad6
--- /dev/null
@@ -0,0 +1,13 @@
+Revision history for Perl extension Pspp.
+
+0.7.0 Sun Jan 11 10:35:56 2009
+      Integrated the module into Pspp's build environment. Added support for 
+      reading from an existing system file.
+
+0.4.3 Sat May 19 14:24:05 2007
+       - first release
+
+0.01  Fri Apr  6 14:13:45 2007
+       - original version; created by h2xs 1.23 with options
+               -A -n Pspp pspp/src/libpspp/version.h
+
diff --git a/perl-module/Examples.pod b/perl-module/Examples.pod
new file mode 100644 (file)
index 0000000..cb286ca
--- /dev/null
@@ -0,0 +1,146 @@
+=pod
+
+=head1 PSPP::Examples
+
+This page shows some simple examples of using the PSPP module.
+See L<PSPP> for details on each of the subroutines.
+
+=head2 A Simple example
+
+This example creates a system file called F<foo.sav>, containing one 
+variable called "id".  It contains no data.
+
+       use PSPP;
+
+       my $dict = PSPP::Dict->new ();
+       my $var = PSPP::Var->new ($dict, "id");
+
+       my $sysfile = PSPP::Sysfile->new ("foo.sav", $dict);
+       $sysfile->close();
+
+
+=head2 A slightly more complex example
+
+In this example there are three variables, called "id", "name" and "dob".
+Their formats are F2.0, A80 and DATETIME17 respectively.
+
+       use PSPP;
+
+       my $dict = PSPP::Dict->new ();
+       PSPP::Var->new ($dict, "id",
+                  (fmt=>PSPP::Fmt::F, width=>2, decimals=>0) );
+       
+       PSPP::Var->new ($dict, "name", (fmt=>PSPP::Fmt::A, width=>80) );
+       PSPP::Var->new ($dict, "dob",  (fmt=>PSPP::Fmt::DATETIME) );
+
+       my $sysfile = PSPP::Sysfile->new ("foo.sav", $dict);
+       $sysfile->close();
+
+=head2 Changing the properties of variables
+
+After a variable has been created, parameters may be set for it.
+
+       use PSPP;
+
+       my $dict = PSPP::Dict->new ();
+       my $var1 = PSPP::Var->new ($dict, "id");
+
+       $var1->set_label ("A unique identifier");
+       $var1->add_value_label (0, "Zero");
+       $var1->add_value_label (1, "One");
+
+
+=head2 Appending data to the file
+
+When a file is created, it contains no data.  Data is added by
+appending cases to the file.
+
+This example creates a file with 3 cases.
+
+       use PSPP;
+
+       my $dict = PSPP::Dict->new ();
+       PSPP::Var->new ($dict, "id", 
+          (fmt=>PSPP::Fmt::F, width=>2, decimals=>0) );
+
+       PSPP::Var->new ($dict, "name", (fmt=>PSPP::Fmt::A, width=>8) );
+
+       my $sysfile = PSPP::Sysfile->new ("foo.sav", $dict);
+
+       $sysfile->append_case ( [1, "Alf"] );
+       $sysfile->append_case ( [2, "Bert"] );
+       $sysfile->append_case ( [3, "Charlie"] );
+
+       $sysfile->close();
+
+=head2  Variables with differing input and output formats
+
+By default,  a variable's output format corresponds to the input format.
+However, the output format may be changed after the variable has 
+been created.
+
+This example shows how  to create a DATETIME variable using the current time
+as its value.  Since pspp uses a different epoch to perl, the constant 
+PSPP::PERL_EPOCH needs to be added to the value returned from time(), in order 
+that it be correctly represented by pspp.
+
+       use PSPP;
+
+       my $dict = PSPP::Dict->new ();
+
+       my $var1 = PSPP::Var->new ($dict, "entrytime", 
+               (fmt=>PSPP::Fmt::F) );
+
+       $var1->set_output_format ( (fmt=>PSPP::Fmt::DATETIME, width=>20) );
+
+       my $sysfile = PSPP::Sysfile->new ("foo.sav", $dict);
+
+       my $now = time ();
+
+       $sysfile->append_case ( [ $now  + PSPP::PERL_EPOCH]  ) 
+               || die "Cant write case";
+       
+       $sysfile->close();
+
+=head2  Reading data
+
+Data can be read from a system file or other source:
+
+       use PSPP;
+
+       my $sf = PSPP::Reader->open ("foo.sav");
+
+       my $dict = $sf->get_dict ();
+
+
+Once opened, the dictionary can be used like any other.
+
+       for ($v = 0 ; $v < $dict->get_var_cnt() ; $v++)
+       {
+           my $var = $dict->get_var ($v);
+
+           # Print the variables
+           my $name = $var->get_name ();
+           my $label = $var->get_label ();
+           print "Var: $name, Label: $label\n";
+
+           # Retrieve and print the value labels
+           my $vl = $var->get_value_labels ();
+           print "$_: $vl->{$_}\n" for keys %$vl;
+       }
+
+
+Reading of data must be done sequentially using the C<get_next_case> method.
+
+       while (my $c = $sf->get_next_case () )
+       {
+           my $v;
+           for ($v = 0; $v < $dict->get_var_cnt(); $v++)
+           {
+               print "val$v: @$c[$v] ";
+           }
+           print "\n";
+       }
+
+
+=cut
\ No newline at end of file
diff --git a/perl-module/MANIFEST b/perl-module/MANIFEST
new file mode 100644 (file)
index 0000000..2546905
--- /dev/null
@@ -0,0 +1,13 @@
+Changes
+const-c.inc
+const-xs.inc
+COPYING
+Examples.pod
+lib/PSPP.pm
+Makefile.PL
+MANIFEST
+ppport.h
+PSPP.xs
+README
+t/Pspp.t
+typemap
diff --git a/perl-module/Makefile.PL b/perl-module/Makefile.PL
new file mode 100644 (file)
index 0000000..045b4e7
--- /dev/null
@@ -0,0 +1,52 @@
+use 5.008008;
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+
+
+do 'pspp-module-config' || do {
+    my $build = prompt ("Enter the location of the build directory of the configured pspp source:", "" );
+    my $src = $top_srcdir;
+
+    %Locations = (SourceDir => "$src", BuildDir => "$build");
+};
+
+WriteMakefile(
+    FULLPERL          => "PSPP_TEST_CMD=\"$Locations{BuildDir}/src/ui/terminal/pspp -B $Locations{SourceDir}/config\" \$(PERL)",
+    NAME              => 'PSPP',
+    DISTNAME          => 'PSPP-Perl',
+    VERSION_FROM      => "$Locations{BuildDir}/src/libpspp/version.c", 
+    PREREQ_PM         => {POSIX=>0}, 
+    PM                => {"lib/PSPP.pm", "\$(INST_LIBDIR)/PSPP.pm"},
+    ($] >= 5.005 ?     ## Add these new keywords supported since 5.005
+      (ABSTRACT_FROM  => 'lib/PSPP.pm', # retrieve abstract from module
+       AUTHOR         => 'John Darrington <john@darrington.wattle.id.au>') : ()),
+    INC       => "-I $Locations{SourceDir}  -I $Locations{SourceDir}/src -I $Locations{SourceDir}/gl -I $Locations{BuildDir}/gl -I $Locations{BuildDir}", 
+    MYEXTLIB  => "$Locations{BuildDir}/src/.libs/libpspp-core.\$(DLEXT)",
+    MAN3PODS  => {"lib/PSPP.pm", "\$(INST_MAN3DIR)/PSPP.3pm",
+           "Examples.pod", "\$(INST_MAN3DIR)/PSPP::Examples.3pm"}
+);
+
+if  (eval {require ExtUtils::Constant; 1}) {
+  # If you edit these definitions to change the constants used by this module,
+  # you will need to use the generated const-c.inc and const-xs.inc
+  # files to replace their "fallback" counterparts before distributing your
+  # changes.
+  my @names = (qw());
+  ExtUtils::Constant::WriteConstants(
+                                     NAME         => 'PSPP',
+                                     NAMES        => \@names,
+                                     DEFAULT_TYPE => 'IV',
+                                     C_FILE       => 'const-c.inc',
+                                     XS_FILE      => 'const-xs.inc',
+                                  );
+
+}
+else {
+  use File::Copy;
+  use File::Spec;
+  foreach my $file ('const-c.inc', 'const-xs.inc') {
+    my $fallback = File::Spec->catfile('fallback', $file);
+    copy ($fallback, $file) or die "Can't copy $fallback to $file: $!";
+  }
+}
diff --git a/perl-module/PSPP.bs b/perl-module/PSPP.bs
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/perl-module/PSPP.xs b/perl-module/PSPP.xs
new file mode 100644 (file)
index 0000000..237ae95
--- /dev/null
@@ -0,0 +1,694 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2007, 2008, 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 the Free Software Foundation; either version 2 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, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
+
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include <config.h>
+
+#include "ppport.h"
+
+#include "minmax.h"
+#include <libpspp/message.h>
+#include <libpspp/version.h>
+#include <gl/xalloc.h>
+#include <data/dictionary.h>
+#include <data/case.h>
+#include <data/casereader.h>
+#include <data/variable.h>
+#include <data/attributes.h>
+#include <data/file-handle-def.h>
+#include <data/sys-file-writer.h>
+#include <data/sys-file-reader.h>
+#include <data/value.h>
+#include <data/value-labels.h>
+#include <data/format.h>
+#include <data/data-in.h>
+#include <string.h>
+
+typedef struct fmt_spec input_format ;
+typedef struct fmt_spec output_format ;
+
+
+/*  A thin wrapper around sfm_writer */
+struct sysfile_info
+{
+  bool opened;
+
+  /* A pointer to the writer. The writer is owned by the struct */
+  struct casewriter *writer;
+
+  /* A pointer to the dictionary. Owned externally */
+  const struct dictionary *dict;
+
+  /* The scalar containing the dictionary */
+  SV *dict_sv;
+};
+
+
+/*  A thin wrapper around sfm_reader */
+struct sysreader_info
+{
+  struct sfm_read_info opts;
+
+  /* A pointer to the reader. The reader is owned by the struct */
+  struct casereader *reader;
+
+  /* A pointer to the dictionary. */
+  struct dictionary *dict;
+};
+
+
+
+/*  A message handler which writes messages to PSPP::errstr */
+static void
+message_handler (const struct msg *m)
+{
+ SV *errstr = get_sv("PSPP::errstr", TRUE);
+ sv_setpv (errstr, m->text);
+}
+
+static int
+sysfile_close (struct sysfile_info *sfi)
+{
+  int retval ;
+  if ( ! sfi->opened )
+    return 0;
+
+  retval = casewriter_destroy (sfi->writer);
+  if (retval > 0 )
+    sfi->opened = false;
+
+  return retval;
+}
+
+static void
+scalar_to_value (union value *val, SV *scalar, const struct variable *var)
+{
+  if ( var_is_numeric (var))
+    {
+       if ( SvNOK (scalar) || SvIOK (scalar) )
+          val->f = SvNV (scalar);
+       else
+          val->f = SYSMIS;
+    }
+  else
+    {
+       STRLEN len;
+       const char *p = SvPV (scalar, len);
+       memset (val->s, ' ', var_get_width (var));
+       memcpy (val->s, p, len);
+    }
+}
+
+
+static SV *
+value_to_scalar (const union value *val, const struct variable *var)
+{
+  if ( var_is_numeric (var))
+    {
+      if ( var_is_value_missing (var, val, MV_SYSTEM))
+       return newSVpvn ("", 0);
+
+      return newSVnv (val->f);
+    }
+  else
+    return newSVpvn (val->s, var_get_width (var));
+}
+
+
+static void
+var_set_input_format (struct variable *v, input_format ip_fmt)
+{
+  struct fmt_spec *if_copy = malloc (sizeof (*if_copy));
+  memcpy (if_copy, &ip_fmt, sizeof (ip_fmt));
+  var_attach_aux (v, if_copy, var_dtor_free);
+}
+
+static union value *
+make_value_from_scalar (SV *val, const struct variable *var)
+{
+ union value *uv = value_create (var_get_width (var));
+ scalar_to_value (uv, val, var);
+ return uv;
+}
+
+
+MODULE = PSPP
+
+MODULE = PSPP          PACKAGE = PSPP
+
+void
+onBoot (ver)
+ const char *ver
+CODE:
+ assert (0 == strcmp (ver, bare_version));
+ msg_init (NULL, message_handler);
+ settings_init (0, 0);
+ fh_init ();
+
+SV *
+format_value (val, var)
+ SV *val
+ struct variable *var
+CODE:
+ SV *ret;
+ const struct fmt_spec *fmt = var_get_print_format (var);
+ union value *uv = make_value_from_scalar (val, var);
+ char *s;
+ s = malloc (fmt->w);
+ memset (s, '\0', fmt->w);
+ data_out (uv, fmt, s);
+ free (uv);
+ ret = newSVpv (s, fmt->w);
+ free (s);
+ RETVAL = ret;
+ OUTPUT:
+RETVAL
+
+
+int
+value_is_missing (val, var)
+ SV *val
+ struct variable *var
+CODE:
+ union value *uv = make_value_from_scalar (val, var);
+ int ret = var_is_value_missing (var, uv, MV_ANY);
+ free (uv);
+ RETVAL = ret;
+ OUTPUT:
+RETVAL
+
+
+
+MODULE = PSPP          PACKAGE = PSPP::Dict
+
+struct dictionary *
+pxs_dict_new()
+CODE:
+ RETVAL = dict_create ();
+OUTPUT:
+ RETVAL
+
+
+void
+DESTROY (dict)
+ struct dictionary *dict
+CODE:
+ dict_destroy (dict);
+
+
+int
+get_var_cnt (dict)
+ struct dictionary *dict
+CODE:
+ RETVAL = dict_get_var_cnt (dict);
+OUTPUT:
+RETVAL
+
+void
+set_label (dict, label)
+ struct dictionary *dict
+ char *label
+CODE:
+ dict_set_label (dict, label);
+
+void
+set_documents (dict, docs)
+ struct dictionary *dict
+ char *docs
+CODE:
+ dict_set_documents (dict, docs);
+
+
+void
+add_document (dict, doc)
+ struct dictionary *dict
+ char *doc
+CODE:
+ dict_add_document_line (dict, doc);
+
+
+void
+clear_documents (dict)
+ struct dictionary *dict
+CODE:
+ dict_clear_documents (dict);
+
+
+void
+set_weight (dict, var)
+ struct dictionary *dict
+ struct variable *var
+CODE:
+ dict_set_weight (dict, var);
+
+
+struct variable *
+pxs_get_variable (dict, idx)
+ struct dictionary *dict
+ SV *idx
+INIT:
+ SV *errstr = get_sv("PSPP::errstr", TRUE);
+ sv_setpv (errstr, "");
+ if ( SvIV (idx) >= dict_get_var_cnt (dict))
+  {
+    sv_setpv (errstr, "The dictionary doesn't have that many variables.");
+    XSRETURN_UNDEF;
+  }
+CODE:
+ RETVAL = dict_get_var (dict, SvIV (idx));
+ OUTPUT:
+RETVAL
+
+
+struct variable *
+pxs_get_var_by_name (dict, name)
+ struct dictionary *dict
+ const char *name
+INIT:
+ SV *errstr = get_sv("PSPP::errstr", TRUE);
+ sv_setpv (errstr, "");
+CODE:
+ struct variable *var = dict_lookup_var (dict, name);
+ if ( ! var )
+      sv_setpv (errstr, "No such variable.");
+ RETVAL = var;
+ OUTPUT:
+RETVAL
+
+
+MODULE = PSPP          PACKAGE = PSPP::Var
+
+
+struct variable *
+pxs_dict_create_var (dict, name, ip_fmt)
+ struct dictionary * dict
+ char *name
+ input_format ip_fmt
+INIT:
+ SV *errstr = get_sv("PSPP::errstr", TRUE);
+ sv_setpv (errstr, "");
+ if ( ! var_is_plausible_name (name, false))
+  {
+    sv_setpv (errstr, "The variable name is not valid.");
+    XSRETURN_UNDEF;
+  }
+CODE:
+ struct fmt_spec op_fmt;
+
+ struct variable *v;
+ op_fmt = fmt_for_output_from_input (&ip_fmt);
+ v = dict_create_var (dict, name,
+       fmt_is_string (op_fmt.type) ? op_fmt.w : 0);
+ if ( NULL == v )
+  {
+    sv_setpv (errstr, "The variable could not be created (probably already exists).");
+    XSRETURN_UNDEF;
+  }
+ var_set_both_formats (v, &op_fmt);
+ var_set_input_format (v, ip_fmt);
+ RETVAL = v;
+OUTPUT:
+ RETVAL
+
+
+int
+set_missing_values (var, v1, ...)
+ struct variable *var;
+ SV *v1;
+INIT:
+ int i;
+ union value val[3];
+
+ if ( items > 4 )
+  croak ("No more than 3 missing values are permitted");
+
+ for (i = 0; i < items - 1; ++i)
+   scalar_to_value (&val[i], ST(i+1), var);
+CODE:
+ struct missing_values mv;
+ mv_init (&mv, var_get_width (var));
+ for (i = 0 ; i < items - 1; ++i )
+   mv_add_value (&mv, &val[i]);
+ var_set_missing_values (var, &mv);
+
+
+void
+set_label (var, label)
+ struct variable *var;
+ char *label
+CODE:
+  var_set_label (var, label);
+
+
+void
+clear_value_labels (var)
+ struct variable *var;
+CODE:
+ var_clear_value_labels (var);
+
+void
+pxs_set_write_format (var, fmt)
+ struct variable *var
+ output_format fmt
+CODE:
+ var_set_write_format (var, &fmt);
+
+
+void
+pxs_set_print_format (var, fmt)
+ struct variable *var
+ output_format fmt
+CODE:
+ var_set_print_format (var, &fmt);
+
+void
+pxs_set_output_format (var, fmt)
+ struct variable *var
+ output_format fmt
+CODE:
+ var_set_both_formats (var, &fmt);
+
+
+int
+add_value_label (var, key, label)
+ struct variable *var
+ SV *key
+ char *label
+INIT:
+ SV *errstr = get_sv("PSPP::errstr", TRUE);
+ sv_setpv (errstr, "");
+CODE:
+ union value the_value;
+
+ if ( var_is_numeric (var))
+ {
+  if ( ! looks_like_number (key))
+    {
+      sv_setpv (errstr, "Cannot add label with string key to a numeric variable");
+      XSRETURN_IV (0);
+    }
+  the_value.f = SvNV (key);
+ }
+ else
+ {
+   if ( var_is_long_string (var) )
+     {
+      sv_setpv (errstr, "Cannot add label to a long string variable");
+      XSRETURN_IV (0);
+     }
+  strncpy (the_value.s, SvPV_nolen(key), MAX_SHORT_STRING);
+ }
+ if (! var_add_value_label (var, &the_value, label) )
+ {
+   sv_setpv (errstr, "Something went wrong");
+   XSRETURN_IV (0);
+ }
+ XSRETURN_IV (1);
+
+
+SV *
+get_attributes (var)
+ struct variable *var
+CODE:
+ HV *attrhash = (HV *) sv_2mortal ((SV *) newHV());
+
+ struct attrset *as = var_get_attributes (var);
+
+ if ( as )
+   {
+     struct attrset_iterator iter;
+     struct attribute *attr;
+
+     for (attr = attrset_first (as, &iter);
+         attr;
+         attr = attrset_next (as, &iter))
+       {
+        int i;
+        const char *name = attribute_get_name (attr);
+
+        AV *values = newAV ();
+
+        for (i = 0 ; i < attribute_get_n_values (attr); ++i )
+          {
+            const char *value = attribute_get_value (attr, i);
+            av_push (values, newSVpv (value, 0));
+          }
+
+        hv_store (attrhash, name, strlen (name),
+                  newRV_noinc ((SV*) values), 0);
+       }
+   }
+
+ RETVAL = newRV ((SV *) attrhash);
+ OUTPUT:
+RETVAL
+
+
+const char *
+get_name (var)
+ struct variable * var
+CODE:
+ RETVAL = var_get_name (var);
+ OUTPUT:
+RETVAL
+
+
+const char *
+get_label (var)
+ struct variable * var
+CODE:
+ RETVAL = var_get_label (var);
+ OUTPUT:
+RETVAL
+
+
+SV *
+get_value_labels (var)
+ struct variable *var
+CODE:
+ HV *labelhash = (HV *) sv_2mortal ((SV *) newHV());
+ struct val_lab *vl;
+ struct val_labs_iterator *viter = NULL;
+ const struct val_labs *labels = var_get_value_labels (var);
+
+ if ( labels )
+   {
+     for (vl = val_labs_first (labels, &viter);
+         vl;
+         vl = val_labs_next (labels, &viter))
+       {
+        SV *sv = value_to_scalar (&vl->value, var);
+        STRLEN len;
+        const char *s = SvPV (sv, len);
+        hv_store (labelhash, s, len, newSVpv (vl->label, 0), 0);
+       }
+   }
+
+ RETVAL = newRV ((SV *) labelhash);
+ OUTPUT:
+RETVAL
+
+
+
+MODULE = PSPP          PACKAGE = PSPP::Sysfile
+
+
+struct sysfile_info *
+pxs_create_sysfile (name, dict_ref, opts_hr)
+ char *name
+ SV *dict_ref
+ SV *opts_hr
+INIT:
+ SV *dict_sv = SvRV (dict_ref);
+ struct dictionary *dict = (void *) SvIV (dict_sv);
+ struct sfm_write_options opts;
+ if (!SvROK (opts_hr))
+  {
+    opts = sfm_writer_default_options ();
+  }
+ else
+  {
+    HV *opt_h = (HV *) SvRV (opts_hr);
+    SV** readonly = hv_fetch(opt_h, "readonly", 8, 0);
+    SV** compress = hv_fetch(opt_h, "compress", 8, 0);
+    SV** version = hv_fetch(opt_h, "version", 7, 0);
+
+    opts.create_writeable = readonly ? ! SvIV (*readonly) : true;
+    opts.compress = compress ? SvIV (*compress) : false;
+    opts.version = version ? SvIV (*version) : 3 ;
+  }
+CODE:
+ struct file_handle *fh =
+  fh_create_file (NULL, name, fh_default_properties () );
+ struct sysfile_info *sfi = xmalloc (sizeof (*sfi));
+ sfi->writer = sfm_open_writer (fh, dict, opts);
+ sfi->dict = dict;
+ sfi->opened = true;
+ sfi->dict_sv = dict_sv;
+ SvREFCNT_inc (sfi->dict_sv);
+ RETVAL = sfi;
+ OUTPUT:
+RETVAL
+
+int
+close (sfi)
+ struct sysfile_info *sfi
+CODE:
+ RETVAL = sysfile_close (sfi);
+OUTPUT:
+ RETVAL
+
+void
+DESTROY (sfi)
+ struct sysfile_info *sfi
+CODE:
+ sysfile_close (sfi);
+ SvREFCNT_dec (sfi->dict_sv);
+ free (sfi);
+
+int
+append_case (sfi, ccase)
+ struct sysfile_info *sfi
+ SV *ccase
+INIT:
+ SV *errstr = get_sv("PSPP::errstr", TRUE);
+ sv_setpv (errstr, "");
+ if ( (!SvROK(ccase)))
+  {
+    XSRETURN_UNDEF;
+  }
+CODE:
+ int i = 0;
+ AV *av_case = (AV*) SvRV (ccase);
+
+ const struct variable **vv;
+ size_t nv;
+ struct ccase *c;
+ SV *sv;
+
+ if ( av_len (av_case) >= dict_get_var_cnt (sfi->dict))
+   XSRETURN_UNDEF;
+
+ c =  case_create (dict_get_next_value_idx (sfi->dict));
+
+ dict_get_vars (sfi->dict, &vv, &nv, 1u << DC_ORDINARY | 1u << DC_SYSTEM);
+
+ for (sv = av_shift (av_case); SvOK (sv);  sv = av_shift (av_case))
+ {
+    const struct variable *v = vv[i++];
+    const struct fmt_spec *ifmt = var_get_aux (v);
+
+    /* If an input format has been set, then use it.
+       Otherwise just convert the raw value.
+    */
+    if ( ifmt )
+      {
+       struct substring ss = ss_cstr (SvPV_nolen (sv));
+       if ( ! data_in (ss, LEGACY_NATIVE, ifmt->type, 0, 0, 0,
+                       case_data_rw (c, v),
+                       var_get_width (v)) )
+         {
+           RETVAL = 0;
+           goto finish;
+         }
+      }
+    else
+      {
+       scalar_to_value (case_data_rw (c, v), sv, v);
+      }
+ }
+
+ /* The remaining variables must be sysmis or blank string */
+ while (i < dict_get_var_cnt (sfi->dict))
+ {
+   const struct variable *v = vv[i++];
+   union value *val = case_data_rw (c, v);
+   if ( var_is_numeric (v))
+       val->f = SYSMIS;
+   else
+       memset (val->s, ' ', var_get_width (v));
+ }
+ RETVAL = casewriter_write (sfi->writer, c);
+ finish:
+ free (vv);
+OUTPUT:
+ RETVAL
+
+
+\f
+
+MODULE = PSPP          PACKAGE = PSPP::Reader
+
+struct sysreader_info *
+pxs_open_sysfile (name)
+ char * name
+CODE:
+ struct casereader *reader;
+ struct sysreader_info *sri = NULL;
+ struct file_handle *fh =
+        fh_create_file (NULL, name, fh_default_properties () );
+
+ sri = xmalloc (sizeof (*sri));
+ sri->reader = sfm_open_reader (fh, &sri->dict, &sri->opts);
+
+ if ( NULL == sri->reader)
+ {
+   free (sri);
+   sri = NULL;
+ }
+
+ RETVAL = sri;
+ OUTPUT:
+RETVAL
+
+
+struct dictionary *
+pxs_get_dict (reader)
+ struct sysreader_info *reader;
+CODE:
+ RETVAL = reader->dict;
+ OUTPUT:
+RETVAL
+
+
+void
+get_next_case (sfr)
+ struct sysreader_info *sfr;
+PPCODE:
+ struct ccase *c;
+
+ if (c = casereader_read (sfr->reader))
+ {
+  int v;
+
+  EXTEND (SP, dict_get_var_cnt (sfr->dict));
+  for (v = 0; v < dict_get_var_cnt (sfr->dict); ++v )
+    {
+      const struct variable *var = dict_get_var (sfr->dict, v);
+      const union value *val = case_data (c, var);
+
+      PUSHs (sv_2mortal (value_to_scalar (val, var)));
+    }
+
+  case_unref (c);
+ }
diff --git a/perl-module/README b/perl-module/README
new file mode 100644 (file)
index 0000000..74d6220
--- /dev/null
@@ -0,0 +1,48 @@
+PSPP version 0.7
+================
+
+This module provides an interface allowing perl programs to create pspp 
+system files.
+
+INSTALLATION
+
+To install you must have first installed and built pspp 0.7.2 or
+later.  Pspp is not required to use this module, only to install
+it. 
+
+To install this module type the following:
+
+   perl Makefile.PL
+   make
+   make test
+   make install
+
+
+
+DEPENDENCIES
+
+This module requires the POSIX module.
+
+The modules Test::More, Text::Diff, File::Temp and the pspp source are
+required during installation, but are not needed to run the module.
+
+
+COPYRIGHT AND LICENCE
+
+Copyright (C) 2007, 2009 by 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 2 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, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
diff --git a/perl-module/automake.mk b/perl-module/automake.mk
new file mode 100644 (file)
index 0000000..0b6c1e0
--- /dev/null
@@ -0,0 +1,70 @@
+## Process this file with automake to produce Makefile.in  -*- makefile -*-
+
+# PSPP
+
+module_sources = \
+ perl-module/Changes \
+ perl-module/COPYING \
+ perl-module/Examples.pod \
+ perl-module/Makefile.PL \
+ perl-module/MANIFEST \
+ perl-module/ppport.h \
+ perl-module/PSPP.xs \
+ perl-module/README \
+ perl-module/typemap \
+ perl-module/lib/PSPP.pm \
+ perl-module/t/Pspp.t
+
+perl-module/pspp-module-config: Makefile
+       target=`mktemp`;\
+       echo '%Locations = (' > $$target ;\
+       printf "  SourceDir => '" >> $$target ;\
+       (cd $(top_srcdir) && echo `pwd`\', ) >> $$target ;\
+       printf "  BuildDir => '" >> $$target ;\
+       (cd $(top_builddir) && echo `pwd`\' ) >> $$target ;\
+       echo ');' >> $$target ;\
+       cp $$target $(top_builddir)/perl-module/pspp-module-config
+
+perl-module/Makefile: perl-module/Makefile.PL perl-module/pspp-module-config
+       cd perl-module && $(PERL) Makefile.PL PREFIX=$(prefix)
+
+perl-module/PSPP-Perl-$(VERSION).tar.gz: $(module_sources)
+       $(RM) $@
+       cd perl-module && $(MAKE) $(AM_MAKEFLAGS) tardist
+
+PHONY += module-make
+module-make: perl-module/Makefile
+       cd perl-module && $(MAKE) $(AM_MAKEFLAGS)
+
+all-local: 
+       if test x"$(top_builddir)" != x"$(top_srcdir)" ; then \
+        for f in $(module_sources); do \
+         destdir=`dirname $$f` ;\
+         mkdir -p $$destdir ;\
+         if test "$(top_srcdir)/$$f" -nt "$(top_builddir)/$$f" ; then \
+                cp $(top_srcdir)/$$f $$destdir ; \
+                echo cp $(top_srcdir)/$$f $$destdir ; \
+         fi ; \
+        done \
+       fi
+       $(MAKE) $(AM_MAKEFLAGS) module-make perl-module/PSPP-Perl-$(VERSION).tar.gz
+
+check-local:
+       loc=`pwd` ; cd $(top_builddir)/src/.libs ; llp=`pwd` ; cd $$loc ;  \
+       LANG=C LD_LIBRARY_PATH=$$llp sh -c "cd perl-module && $(MAKE) $(AM_MAKEFLAGS) test"
+
+
+clean-local:
+       cd perl-module && $(MAKE) $(AM_MAKEFLAGS) clean
+       if test x"$(top_builddir)" != x"$(top_srcdir)" ; then \
+         $(RM) $(module_sources) ; \
+       fi
+       $(RM) perl-module/Makefile.old
+
+CLEANFILES += \
+        perl-module/PSPP-Perl-$(VERSION).tar.gz \
+       perl-module/pspp-module-config \
+       perl-module/const-c.inc \
+       perl-module/const-xs.inc 
+
+EXTRA_DIST +=  $(module_sources)
diff --git a/perl-module/lib/PSPP.pm b/perl-module/lib/PSPP.pm
new file mode 100644 (file)
index 0000000..3cb9f3b
--- /dev/null
@@ -0,0 +1,550 @@
+use 5.008008;
+use strict;
+use warnings;
+
+=head1 NAME
+
+PSPP-Perl - Perl extension to PSPP
+
+=head1 SYNOPSIS
+
+  use PSPP;
+
+=head1 DESCRIPTION
+
+PSPP-Perl provides an interface to the libraries used by pspp to read and
+write system files.  
+
+=head1 EXPORT
+
+None by default.
+
+=cut
+BEGIN {
+       $PSPP::VERSION='0.7.2';
+       require XSLoader;
+       XSLoader::load('PSPP', $PSPP::VERSION);
+}
+
+PSPP::onBoot($PSPP::VERSION);
+
+=pod
+
+=head1 PROGRAMMER'S INTERFACE
+
+The subroutines in this package return zero or unref on error.
+When errors occur, a string describing the error is written 
+to C<$PSPP::errstr>. 
+
+=cut
+
+package PSPP;
+use POSIX ;
+
+use constant { SYSMIS => -(POSIX::DBL_MAX), 
+              PERL_EPOCH => 12219379200 # Number of seconds between 
+                   # 14th October 1582
+                  # and 
+                  # 1st January 1970 
+              };
+
+
+
+package PSPP::Dict;
+
+=pod
+
+=head2 PSPP::Dict::new
+
+Creates a new dictionary.  This returned dictionary will be empty.
+Returns undef on failure.
+
+=head3 set_documents ($string)
+
+Sets the documents (comments) to C<string>.
+
+=head3 add_document ($string)
+
+Appends C<string> to the documents.
+
+=head3 clear_documents ()
+
+Removes all documents.
+
+=head3 set_weight ($var)
+
+Sets the weighting variable to C<var>.
+
+=cut
+
+sub new
+{
+    my $class = shift;
+    my $self = pxs_dict_new ();
+    bless ($self, $class);
+    return $self;
+}
+
+=pod
+
+=head3 get_var_cnt ()
+
+Returns the number of variables in the dictionary.
+
+=head3 get_var ($idx)
+
+Returns the C<idx>th variable from the dictionary.
+Returns undef if C<idx> is greater than or equal to the number
+of variables in the dictionary.
+
+=cut
+
+sub get_var
+{
+    my $dict = shift;
+    my $idx = shift;
+    my $var = pxs_get_variable ($dict, $idx);
+
+    if ( ref $var ) 
+    {
+       bless ($var, "PSPP::Var");
+    }
+    return $var;
+}
+
+=pod
+
+=head3 get_var_by_name ($name)
+
+Returns the variable from the dictionary whose name is C<name>.
+If there is no such variable, a null reference will be returned.
+
+=cut
+
+sub get_var_by_name
+{
+    my $dict = shift;
+    my $name = shift;
+    my $var = pxs_get_var_by_name ($dict, $name);
+
+    if ( ref $var ) 
+    {
+       bless ($var, "PSPP::Var");
+    }
+    return $var;
+}
+
+
+package PSPP::Fmt;
+
+=pod
+
+=head2 PSPP::Fmt
+
+Contains constants used to denote variable format types.  
+The identifiers are the same as  those used in pspp to denote formats.
+For  example C<PSPP::Fmt::F> defines floating point format, and
+C<PSPP::Fmt::A> denotes string format.
+
+=cut
+
+# These must correspond to the values in src/data/format.h
+use constant {
+    F =>        0,
+    COMMA =>    1,
+    DOT =>      2, 
+    DOLLAR =>   3, 
+    PCT =>      4, 
+    E =>        5, 
+    CCA =>      6, 
+    CCB =>      7, 
+    CCC =>      8, 
+    CCD =>      9, 
+    CCE =>      10, 
+    N =>        11, 
+    Z =>        12, 
+    P =>        13, 
+    PK =>       14, 
+    IB =>       15, 
+    PIB =>      16, 
+    PIBHEX =>   17, 
+    RB =>       18, 
+    RBHEX =>    19, 
+    DATE =>     20, 
+    ADATE =>    21, 
+    EDATE =>    22, 
+    JDATE =>    23, 
+    SDATE =>    24, 
+    QYR =>      25, 
+    MOYR =>     26, 
+    WKYR =>     27, 
+    DATETIME => 28, 
+    TIME =>     29, 
+    DTIME =>    30, 
+    WKDAY =>    31, 
+    MONTH =>    32, 
+    A =>        33, 
+    AHEX =>     34
+};
+
+
+=head2 PSPP::Var
+
+=cut
+
+package PSPP::Var;
+
+=head3 new ($dict, $name, %input_fmt)
+
+Creates and returns a new variable in the dictionary C<dict>.  The 
+new variable will have the name C<name>.
+The input format is set by the C<input_fmt> parameter 
+(See L</PSPP::Fmt>).
+By default, the write and print formats are the same as the input format.
+The write and print formats may be changed (See L</set_write_format>), 
+L</set_print_format>).  The input format may not be changed after
+the variable has been created.
+If the variable cannot be created, undef is returned.
+
+=cut
+
+sub new
+{
+    my $class = shift;
+    my $dict = shift;
+    my $name = shift;
+    my %format = @_;
+    my $self = pxs_dict_create_var ($dict, $name, \%format);
+    if ( ref $self ) 
+    {
+       bless ($self, $class);
+    }
+    return $self;
+}
+
+=pod
+
+=head3 set_label ($label)
+
+Sets the variable label to C<label>.
+
+
+=cut
+
+=pod
+
+=head3 set_write_format (%fmt)
+
+Sets the write format to C<fmt>. <fmt> is a hash containing the keys:
+
+=over 2
+
+=item FMT
+
+A constant denoting the format type.  See L</PSPP::Fmt>.
+
+=item decimals
+
+An integer denoting the number of decimal places for the format.
+
+=item width
+
+An integer denoting the number of width of the format.
+
+=back
+
+On error the subroutine returns zero.
+
+=cut
+
+sub set_write_format
+{
+    my $var = shift;
+    my %format = @_;
+    pxs_set_write_format ($var, \%format);
+}
+
+=pod
+
+=head3 set_print_format (%fmt)
+
+Sets the print format to C<fmt>.
+On error the subroutine returns zero.
+
+=cut
+
+sub set_print_format
+{
+    my $var = shift;
+    my %format = @_;
+    pxs_set_print_format ($var, \%format);
+}
+
+=pod
+
+=head3 set_output_format (%fmt)
+
+Sets the write and print formats to C<fmt>.  This is the same as
+calling set_write_format followed by set_print_format.
+On error the subroutine returns zero.
+
+=cut
+
+
+sub set_output_format
+{
+    my $var = shift;
+    my %format = @_;
+    pxs_set_output_format ($var, \%format);
+}
+
+=pod
+
+=head3 clear_value_labels ()
+
+Removes all value labels from the variable.
+
+=cut
+
+
+=pod
+
+=head3 add_value_label ($key, $label)
+
+Adds the value label C<label> to the variable for the value C<key>.
+On error the subroutine returns zero.
+
+=head3 add_value_labels (@array)
+
+=cut
+
+sub add_value_labels
+{
+    my $var = shift;
+    my %values = @_;
+    my @li;
+
+    my $n = 0;
+    while ( @li = each %values ) 
+    {
+       if ( $var->add_value_label ($li[0], "$li[1]") ) 
+       {
+           $n++;
+       }
+    }
+
+    return $n;
+}
+
+=pod
+
+=head3 set_value_labels ($key, $value)
+
+C<Set_value_labels> is identical to calling L</clear_value_labels>
+followed by L</add_value_labels>.
+On error the subroutine returns zero.
+
+=cut
+
+sub set_value_labels
+{
+    my $self = shift;
+    my %labels = @_;
+    $self->clear_value_labels () ;
+    $self->add_value_labels (%labels);
+}
+
+=pod
+
+=head3 set_missing_values ($val1 [, $val2[, $val3] ])
+
+Sets the missing values for the variable.  
+No more than three missing values may be specified.
+
+=head3 get_attributes()
+
+Returns a reference to a hash of the custom variable attributes.
+Each value of the hash is a reference to an array containing the 
+attribute values.
+
+=head3 get_name ()
+
+Returns the name of the variable.
+
+=head3 get_label ()
+
+Returns the label of the variable or undef if there is no label.
+
+=head3 get_value_labels ()
+
+Returns a reference to a hash containing the value labels for the variable.
+The hash is keyed by data values which correpond to the labels.
+
+=cut
+
+package PSPP::Sysfile;
+
+=pod
+
+=head2 PSPP::Sysfile
+
+=head3 new ($filename, $dict [,%opts])
+
+Creates a new system file from the dictionary C<dict>.  The file will
+be written to the file called C<filename>.
+C<opt>, if specified, is a hash containing optional parameters for the
+system file.  Currently, the only supported parameter is
+C<compress>. If C<compress> is non zero, then the system file written
+will be in the compressed format.
+On error, undef is returned.
+
+
+=head3 append_case (@case)
+
+Appends a case to the system file.
+C<Case> is an array of scalars, each of which are the values of 
+the variables in the dictionary corresponding to the system file.
+The special value C<PSPP::SYSMIS> may be used to indicate that a value
+is system missing.
+If the array contains less elements than variables in the dictionary,
+remaining values will be set to system missing.
+
+=cut
+
+sub new
+{
+    my $class = shift;
+    my $filename = shift;
+    my $dict = shift;
+    my $opts = shift;
+
+    my $self  = pxs_create_sysfile ($filename, $dict, $opts);
+
+    if ( ref $self ) 
+    {
+       bless ($self, $class);
+    }
+    return $self;
+}
+
+=pod
+
+=head3 close ()
+
+Closes the system file.
+
+This subroutine closes the system file and flushes it to disk.  No
+further cases may be written once the file has been closed.
+The system file will be automatically closed when it goes out of scope.
+
+=cut
+
+package PSPP::Reader;
+
+=pod
+
+=head2 PSPP::Reader
+
+=cut
+
+sub open
+{
+    my $class = shift;
+    my $filename = shift;
+
+    my $self  = pxs_open_sysfile ($filename);
+
+    if ( ref $self ) 
+    {
+       bless ($self, $class);
+    }
+    return $self;
+}
+
+=pod
+
+=head3 open ($filename)
+
+Opens a system file for reading.
+
+Open is used to read data from an existing system file. 
+It creates and returns a PSPP::Reader object which can be used to read 
+data and dictionary information from C<filename>.
+
+=cut
+
+sub get_dict
+{
+    my $reader = shift;
+
+    my $dict = pxs_get_dict ($reader);
+
+    bless ($dict, "PSPP::Dict");
+
+    return $dict;
+}
+
+=pod
+
+=head3 get_dict ()
+
+Returns the dictionary associated with the reader.
+
+=head3 get_next_case ()
+
+Retrieves the next case from the reader.
+This method returns an array of scalars, each of which are the values of 
+the data in the system file.
+The first call to C<get_next_case> after C<open> has been called retrieves
+the first case in the system file.  Each subsequent call retrieves the next
+case.  If there are no more cases to be read, the function returns an empty
+list.
+
+If the case contains system missing values, these values are set to the 
+empty string.
+
+=head2 Miscellaneous subroutines
+
+The following subroutines provide (hopefully) useful information about the 
+values retrieved from a reader.
+
+=head3 PSPP::format_value ($value, $variable)
+
+Returns a scalar containing a string representing C<value> formatted accoring 
+to the print format of C<variable>.
+In the most common ussage,  C<value> should be a value of C<variable>.
+
+
+=head3 PSPP::value_is_missing ($value, $variable)
+
+Returns non-zero if C<value> is either system missing, or if it matches the 
+user missing criteria for C<variable>.
+
+=cut
+
+1;
+__END__
+
+
+=head1 AUTHOR
+
+John Darrington, E<lt>john@darrington.wattle.id.auE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2007, 2008, 2009 by 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 <http://www.gnu.org/licenses/>.
+
+=cut
diff --git a/perl-module/ppport.h b/perl-module/ppport.h
new file mode 100644 (file)
index 0000000..181fb2b
--- /dev/null
@@ -0,0 +1,4954 @@
+#if 0
+<<'SKIP';
+#endif
+/*
+----------------------------------------------------------------------
+
+    ppport.h -- Perl/Pollution/Portability Version 3.06_01
+
+    Automatically created by Devel::PPPort running under
+    perl 5.008008 on Fri Apr  6 14:13:45 2007.
+
+    Do NOT edit this file directly! -- Edit PPPort_pm.PL and the
+    includes in parts/inc/ instead.
+
+    Use 'perldoc ppport.h' to view the documentation below.
+
+----------------------------------------------------------------------
+
+SKIP
+
+=pod
+
+=head1 NAME
+
+ppport.h - Perl/Pollution/Portability version 3.06_01
+
+=head1 SYNOPSIS
+
+  perl ppport.h [options] [source files]
+
+  Searches current directory for files if no [source files] are given
+
+  --help                      show short help
+
+  --patch=file                write one patch file with changes
+  --copy=suffix               write changed copies with suffix
+  --diff=program              use diff program and options
+
+  --compat-version=version    provide compatibility with Perl version
+  --cplusplus                 accept C++ comments
+
+  --quiet                     don't output anything except fatal errors
+  --nodiag                    don't show diagnostics
+  --nohints                   don't show hints
+  --nochanges                 don't suggest changes
+  --nofilter                  don't filter input files
+
+  --list-provided             list provided API
+  --list-unsupported          list unsupported API
+  --api-info=name             show Perl API portability information
+
+=head1 COMPATIBILITY
+
+This version of F<ppport.h> is designed to support operation with Perl
+installations back to 5.003, and has been tested up to 5.9.3.
+
+=head1 OPTIONS
+
+=head2 --help
+
+Display a brief usage summary.
+
+=head2 --patch=I<file>
+
+If this option is given, a single patch file will be created if
+any changes are suggested. This requires a working diff program
+to be installed on your system.
+
+=head2 --copy=I<suffix>
+
+If this option is given, a copy of each file will be saved with
+the given suffix that contains the suggested changes. This does
+not require any external programs.
+
+If neither C<--patch> or C<--copy> are given, the default is to
+simply print the diffs for each file. This requires either
+C<Text::Diff> or a C<diff> program to be installed.
+
+=head2 --diff=I<program>
+
+Manually set the diff program and options to use. The default
+is to use C<Text::Diff>, when installed, and output unified
+context diffs.
+
+=head2 --compat-version=I<version>
+
+Tell F<ppport.h> to check for compatibility with the given
+Perl version. The default is to check for compatibility with Perl
+version 5.003. You can use this option to reduce the output
+of F<ppport.h> if you intend to be backward compatible only
+up to a certain Perl version.
+
+=head2 --cplusplus
+
+Usually, F<ppport.h> will detect C++ style comments and
+replace them with C style comments for portability reasons.
+Using this option instructs F<ppport.h> to leave C++
+comments untouched.
+
+=head2 --quiet
+
+Be quiet. Don't print anything except fatal errors.
+
+=head2 --nodiag
+
+Don't output any diagnostic messages. Only portability
+alerts will be printed.
+
+=head2 --nohints
+
+Don't output any hints. Hints often contain useful portability
+notes.
+
+=head2 --nochanges
+
+Don't suggest any changes. Only give diagnostic output and hints
+unless these are also deactivated.
+
+=head2 --nofilter
+
+Don't filter the list of input files. By default, files not looking
+like source code (i.e. not *.xs, *.c, *.cc, *.cpp or *.h) are skipped.
+
+=head2 --list-provided
+
+Lists the API elements for which compatibility is provided by
+F<ppport.h>. Also lists if it must be explicitly requested,
+if it has dependencies, and if there are hints for it.
+
+=head2 --list-unsupported
+
+Lists the API elements that are known not to be supported by
+F<ppport.h> and below which version of Perl they probably
+won't be available or work.
+
+=head2 --api-info=I<name>
+
+Show portability information for API elements matching I<name>.
+If I<name> is surrounded by slashes, it is interpreted as a regular
+expression.
+
+=head1 DESCRIPTION
+
+In order for a Perl extension (XS) module to be as portable as possible
+across differing versions of Perl itself, certain steps need to be taken.
+
+=over 4
+
+=item *
+
+Including this header is the first major one. This alone will give you
+access to a large part of the Perl API that hasn't been available in
+earlier Perl releases. Use
+
+    perl ppport.h --list-provided
+
+to see which API elements are provided by ppport.h.
+
+=item *
+
+You should avoid using deprecated parts of the API. For example, using
+global Perl variables without the C<PL_> prefix is deprecated. Also,
+some API functions used to have a C<perl_> prefix. Using this form is
+also deprecated. You can safely use the supported API, as F<ppport.h>
+will provide wrappers for older Perl versions.
+
+=item *
+
+If you use one of a few functions that were not present in earlier
+versions of Perl, and that can't be provided using a macro, you have
+to explicitly request support for these functions by adding one or
+more C<#define>s in your source code before the inclusion of F<ppport.h>.
+
+These functions will be marked C<explicit> in the list shown by
+C<--list-provided>.
+
+Depending on whether you module has a single or multiple files that
+use such functions, you want either C<static> or global variants.
+
+For a C<static> function, use:
+
+    #define NEED_function
+
+For a global function, use:
+
+    #define NEED_function_GLOBAL
+
+Note that you mustn't have more than one global request for one
+function in your project.
+
+    Function                  Static Request               Global Request
+    -----------------------------------------------------------------------------------------
+    eval_pv()                 NEED_eval_pv                 NEED_eval_pv_GLOBAL
+    grok_bin()                NEED_grok_bin                NEED_grok_bin_GLOBAL
+    grok_hex()                NEED_grok_hex                NEED_grok_hex_GLOBAL
+    grok_number()             NEED_grok_number             NEED_grok_number_GLOBAL
+    grok_numeric_radix()      NEED_grok_numeric_radix      NEED_grok_numeric_radix_GLOBAL
+    grok_oct()                NEED_grok_oct                NEED_grok_oct_GLOBAL
+    newCONSTSUB()             NEED_newCONSTSUB             NEED_newCONSTSUB_GLOBAL
+    newRV_noinc()             NEED_newRV_noinc             NEED_newRV_noinc_GLOBAL
+    sv_2pv_nolen()            NEED_sv_2pv_nolen            NEED_sv_2pv_nolen_GLOBAL
+    sv_2pvbyte()              NEED_sv_2pvbyte              NEED_sv_2pvbyte_GLOBAL
+    sv_catpvf_mg()            NEED_sv_catpvf_mg            NEED_sv_catpvf_mg_GLOBAL
+    sv_catpvf_mg_nocontext()  NEED_sv_catpvf_mg_nocontext  NEED_sv_catpvf_mg_nocontext_GLOBAL
+    sv_setpvf_mg()            NEED_sv_setpvf_mg            NEED_sv_setpvf_mg_GLOBAL
+    sv_setpvf_mg_nocontext()  NEED_sv_setpvf_mg_nocontext  NEED_sv_setpvf_mg_nocontext_GLOBAL
+    vnewSVpvf()               NEED_vnewSVpvf               NEED_vnewSVpvf_GLOBAL
+
+To avoid namespace conflicts, you can change the namespace of the
+explicitly exported functions using the C<DPPP_NAMESPACE> macro.
+Just C<#define> the macro before including C<ppport.h>:
+
+    #define DPPP_NAMESPACE MyOwnNamespace_
+    #include "ppport.h"
+
+The default namespace is C<DPPP_>.
+
+=back
+
+The good thing is that most of the above can be checked by running
+F<ppport.h> on your source code. See the next section for
+details.
+
+=head1 EXAMPLES
+
+To verify whether F<ppport.h> is needed for your module, whether you
+should make any changes to your code, and whether any special defines
+should be used, F<ppport.h> can be run as a Perl script to check your
+source code. Simply say:
+
+    perl ppport.h
+
+The result will usually be a list of patches suggesting changes
+that should at least be acceptable, if not necessarily the most
+efficient solution, or a fix for all possible problems.
+
+If you know that your XS module uses features only available in
+newer Perl releases, if you're aware that it uses C++ comments,
+and if you want all suggestions as a single patch file, you could
+use something like this:
+
+    perl ppport.h --compat-version=5.6.0 --cplusplus --patch=test.diff
+
+If you only want your code to be scanned without any suggestions
+for changes, use:
+
+    perl ppport.h --nochanges
+
+You can specify a different C<diff> program or options, using
+the C<--diff> option:
+
+    perl ppport.h --diff='diff -C 10'
+
+This would output context diffs with 10 lines of context.
+
+To display portability information for the C<newSVpvn> function,
+use:
+
+    perl ppport.h --api-info=newSVpvn
+
+Since the argument to C<--api-info> can be a regular expression,
+you can use
+
+    perl ppport.h --api-info=/_nomg$/
+
+to display portability information for all C<_nomg> functions or
+
+    perl ppport.h --api-info=/./
+
+to display information for all known API elements.
+
+=head1 BUGS
+
+If this version of F<ppport.h> is causing failure during
+the compilation of this module, please check if newer versions
+of either this module or C<Devel::PPPort> are available on CPAN
+before sending a bug report.
+
+If F<ppport.h> was generated using the latest version of
+C<Devel::PPPort> and is causing failure of this module, please
+file a bug report using the CPAN Request Tracker at L<http://rt.cpan.org/>.
+
+Please include the following information:
+
+=over 4
+
+=item 1.
+
+The complete output from running "perl -V"
+
+=item 2.
+
+This file.
+
+=item 3.
+
+The name and version of the module you were trying to build.
+
+=item 4.
+
+A full log of the build that failed.
+
+=item 5.
+
+Any other information that you think could be relevant.
+
+=back
+
+For the latest version of this code, please get the C<Devel::PPPort>
+module from CPAN.
+
+=head1 COPYRIGHT
+
+Version 3.x, Copyright (c) 2004-2005, Marcus Holland-Moritz.
+
+Version 2.x, Copyright (C) 2001, Paul Marquess.
+
+Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 SEE ALSO
+
+See L<Devel::PPPort>.
+
+=cut
+
+use strict;
+
+my %opt = (
+  quiet     => 0,
+  diag      => 1,
+  hints     => 1,
+  changes   => 1,
+  cplusplus => 0,
+  filter    => 1,
+);
+
+my($ppport) = $0 =~ /([\w.]+)$/;
+my $LF = '(?:\r\n|[\r\n])';   # line feed
+my $HS = "[ \t]";             # horizontal whitespace
+
+eval {
+  require Getopt::Long;
+  Getopt::Long::GetOptions(\%opt, qw(
+    help quiet diag! filter! hints! changes! cplusplus
+    patch=s copy=s diff=s compat-version=s
+    list-provided list-unsupported api-info=s
+  )) or usage();
+};
+
+if ($@ and grep /^-/, @ARGV) {
+  usage() if "@ARGV" =~ /^--?h(?:elp)?$/;
+  die "Getopt::Long not found. Please don't use any options.\n";
+}
+
+usage() if $opt{help};
+
+if (exists $opt{'compat-version'}) {
+  my($r,$v,$s) = eval { parse_version($opt{'compat-version'}) };
+  if ($@) {
+    die "Invalid version number format: '$opt{'compat-version'}'\n";
+  }
+  die "Only Perl 5 is supported\n" if $r != 5;
+  die "Invalid version number: $opt{'compat-version'}\n" if $v >= 1000 || $s >= 1000;
+  $opt{'compat-version'} = sprintf "%d.%03d%03d", $r, $v, $s;
+}
+else {
+  $opt{'compat-version'} = 5;
+}
+
+# Never use C comments in this file!!!!!
+my $ccs  = '/'.'*';
+my $cce  = '*'.'/';
+my $rccs = quotemeta $ccs;
+my $rcce = quotemeta $cce;
+
+my %API = map { /^(\w+)\|([^|]*)\|([^|]*)\|(\w*)$/
+                ? ( $1 => {
+                      ($2                  ? ( base     => $2 ) : ()),
+                      ($3                  ? ( todo     => $3 ) : ()),
+                      (index($4, 'v') >= 0 ? ( varargs  => 1  ) : ()),
+                      (index($4, 'p') >= 0 ? ( provided => 1  ) : ()),
+                      (index($4, 'n') >= 0 ? ( nothxarg => 1  ) : ()),
+                    } )
+                : die "invalid spec: $_" } qw(
+AvFILLp|5.004050||p
+AvFILL|||
+CLASS|||n
+CX_CURPAD_SAVE|||
+CX_CURPAD_SV|||
+CopFILEAV|5.006000||p
+CopFILEGV_set|5.006000||p
+CopFILEGV|5.006000||p
+CopFILESV|5.006000||p
+CopFILE_set|5.006000||p
+CopFILE|5.006000||p
+CopSTASHPV_set|5.006000||p
+CopSTASHPV|5.006000||p
+CopSTASH_eq|5.006000||p
+CopSTASH_set|5.006000||p
+CopSTASH|5.006000||p
+CopyD|5.009002||p
+Copy|||
+CvPADLIST|||
+CvSTASH|||
+CvWEAKOUTSIDE|||
+DEFSV|5.004050||p
+END_EXTERN_C|5.005000||p
+ENTER|||
+ERRSV|5.004050||p
+EXTEND|||
+EXTERN_C|5.005000||p
+FREETMPS|||
+GIMME_V||5.004000|n
+GIMME|||n
+GROK_NUMERIC_RADIX|5.007002||p
+G_ARRAY|||
+G_DISCARD|||
+G_EVAL|||
+G_NOARGS|||
+G_SCALAR|||
+G_VOID||5.004000|
+GetVars|||
+GvSV|||
+Gv_AMupdate|||
+HEf_SVKEY||5.004000|
+HeHASH||5.004000|
+HeKEY||5.004000|
+HeKLEN||5.004000|
+HePV||5.004000|
+HeSVKEY_force||5.004000|
+HeSVKEY_set||5.004000|
+HeSVKEY||5.004000|
+HeVAL||5.004000|
+HvNAME|||
+INT2PTR|5.006000||p
+IN_LOCALE_COMPILETIME|5.007002||p
+IN_LOCALE_RUNTIME|5.007002||p
+IN_LOCALE|5.007002||p
+IN_PERL_COMPILETIME|5.008001||p
+IS_NUMBER_GREATER_THAN_UV_MAX|5.007002||p
+IS_NUMBER_INFINITY|5.007002||p
+IS_NUMBER_IN_UV|5.007002||p
+IS_NUMBER_NAN|5.007003||p
+IS_NUMBER_NEG|5.007002||p
+IS_NUMBER_NOT_INT|5.007002||p
+IVSIZE|5.006000||p
+IVTYPE|5.006000||p
+IVdf|5.006000||p
+LEAVE|||
+LVRET|||
+MARK|||
+MY_CXT_CLONE|5.009002||p
+MY_CXT_INIT|5.007003||p
+MY_CXT|5.007003||p
+MoveD|5.009002||p
+Move|||
+NEWSV|||
+NOOP|5.005000||p
+NUM2PTR|5.006000||p
+NVTYPE|5.006000||p
+NVef|5.006001||p
+NVff|5.006001||p
+NVgf|5.006001||p
+Newc|||
+Newz|||
+New|||
+Nullav|||
+Nullch|||
+Nullcv|||
+Nullhv|||
+Nullsv|||
+ORIGMARK|||
+PAD_BASE_SV|||
+PAD_CLONE_VARS|||
+PAD_COMPNAME_FLAGS|||
+PAD_COMPNAME_GEN_set|||
+PAD_COMPNAME_GEN|||
+PAD_COMPNAME_OURSTASH|||
+PAD_COMPNAME_PV|||
+PAD_COMPNAME_TYPE|||
+PAD_RESTORE_LOCAL|||
+PAD_SAVE_LOCAL|||
+PAD_SAVE_SETNULLPAD|||
+PAD_SETSV|||
+PAD_SET_CUR_NOSAVE|||
+PAD_SET_CUR|||
+PAD_SVl|||
+PAD_SV|||
+PERL_BCDVERSION|5.009003||p
+PERL_GCC_BRACE_GROUPS_FORBIDDEN|5.008001||p
+PERL_INT_MAX|5.004000||p
+PERL_INT_MIN|5.004000||p
+PERL_LONG_MAX|5.004000||p
+PERL_LONG_MIN|5.004000||p
+PERL_MAGIC_arylen|5.007002||p
+PERL_MAGIC_backref|5.007002||p
+PERL_MAGIC_bm|5.007002||p
+PERL_MAGIC_collxfrm|5.007002||p
+PERL_MAGIC_dbfile|5.007002||p
+PERL_MAGIC_dbline|5.007002||p
+PERL_MAGIC_defelem|5.007002||p
+PERL_MAGIC_envelem|5.007002||p
+PERL_MAGIC_env|5.007002||p
+PERL_MAGIC_ext|5.007002||p
+PERL_MAGIC_fm|5.007002||p
+PERL_MAGIC_glob|5.007002||p
+PERL_MAGIC_isaelem|5.007002||p
+PERL_MAGIC_isa|5.007002||p
+PERL_MAGIC_mutex|5.007002||p
+PERL_MAGIC_nkeys|5.007002||p
+PERL_MAGIC_overload_elem|5.007002||p
+PERL_MAGIC_overload_table|5.007002||p
+PERL_MAGIC_overload|5.007002||p
+PERL_MAGIC_pos|5.007002||p
+PERL_MAGIC_qr|5.007002||p
+PERL_MAGIC_regdata|5.007002||p
+PERL_MAGIC_regdatum|5.007002||p
+PERL_MAGIC_regex_global|5.007002||p
+PERL_MAGIC_shared_scalar|5.007003||p
+PERL_MAGIC_shared|5.007003||p
+PERL_MAGIC_sigelem|5.007002||p
+PERL_MAGIC_sig|5.007002||p
+PERL_MAGIC_substr|5.007002||p
+PERL_MAGIC_sv|5.007002||p
+PERL_MAGIC_taint|5.007002||p
+PERL_MAGIC_tiedelem|5.007002||p
+PERL_MAGIC_tiedscalar|5.007002||p
+PERL_MAGIC_tied|5.007002||p
+PERL_MAGIC_utf8|5.008001||p
+PERL_MAGIC_uvar_elem|5.007003||p
+PERL_MAGIC_uvar|5.007002||p
+PERL_MAGIC_vec|5.007002||p
+PERL_MAGIC_vstring|5.008001||p
+PERL_QUAD_MAX|5.004000||p
+PERL_QUAD_MIN|5.004000||p
+PERL_REVISION|5.006000||p
+PERL_SCAN_ALLOW_UNDERSCORES|5.007003||p
+PERL_SCAN_DISALLOW_PREFIX|5.007003||p
+PERL_SCAN_GREATER_THAN_UV_MAX|5.007003||p
+PERL_SCAN_SILENT_ILLDIGIT|5.008001||p
+PERL_SHORT_MAX|5.004000||p
+PERL_SHORT_MIN|5.004000||p
+PERL_SUBVERSION|5.006000||p
+PERL_UCHAR_MAX|5.004000||p
+PERL_UCHAR_MIN|5.004000||p
+PERL_UINT_MAX|5.004000||p
+PERL_UINT_MIN|5.004000||p
+PERL_ULONG_MAX|5.004000||p
+PERL_ULONG_MIN|5.004000||p
+PERL_UNUSED_DECL|5.007002||p
+PERL_UQUAD_MAX|5.004000||p
+PERL_UQUAD_MIN|5.004000||p
+PERL_USHORT_MAX|5.004000||p
+PERL_USHORT_MIN|5.004000||p
+PERL_VERSION|5.006000||p
+PL_DBsingle|||pn
+PL_DBsub|||pn
+PL_DBtrace|||n
+PL_Sv|5.005000||p
+PL_compiling|5.004050||p
+PL_copline|5.005000||p
+PL_curcop|5.004050||p
+PL_curstash|5.004050||p
+PL_debstash|5.004050||p
+PL_defgv|5.004050||p
+PL_diehook|5.004050||p
+PL_dirty|5.004050||p
+PL_dowarn|||pn
+PL_errgv|5.004050||p
+PL_hexdigit|5.005000||p
+PL_hints|5.005000||p
+PL_last_in_gv|||n
+PL_modglobal||5.005000|n
+PL_na|5.004050||pn
+PL_no_modify|5.006000||p
+PL_ofs_sv|||n
+PL_perl_destruct_level|5.004050||p
+PL_perldb|5.004050||p
+PL_ppaddr|5.006000||p
+PL_rsfp_filters|5.004050||p
+PL_rsfp|5.004050||p
+PL_rs|||n
+PL_stack_base|5.004050||p
+PL_stack_sp|5.004050||p
+PL_stdingv|5.004050||p
+PL_sv_arenaroot|5.004050||p
+PL_sv_no|5.004050||pn
+PL_sv_undef|5.004050||pn
+PL_sv_yes|5.004050||pn
+PL_tainted|5.004050||p
+PL_tainting|5.004050||p
+POPi|||n
+POPl|||n
+POPn|||n
+POPpbytex||5.007001|n
+POPpx||5.005030|n
+POPp|||n
+POPs|||n
+PTR2IV|5.006000||p
+PTR2NV|5.006000||p
+PTR2UV|5.006000||p
+PTR2ul|5.007001||p
+PTRV|5.006000||p
+PUSHMARK|||
+PUSHi|||
+PUSHmortal|5.009002||p
+PUSHn|||
+PUSHp|||
+PUSHs|||
+PUSHu|5.004000||p
+PUTBACK|||
+PerlIO_clearerr||5.007003|
+PerlIO_close||5.007003|
+PerlIO_eof||5.007003|
+PerlIO_error||5.007003|
+PerlIO_fileno||5.007003|
+PerlIO_fill||5.007003|
+PerlIO_flush||5.007003|
+PerlIO_get_base||5.007003|
+PerlIO_get_bufsiz||5.007003|
+PerlIO_get_cnt||5.007003|
+PerlIO_get_ptr||5.007003|
+PerlIO_read||5.007003|
+PerlIO_seek||5.007003|
+PerlIO_set_cnt||5.007003|
+PerlIO_set_ptrcnt||5.007003|
+PerlIO_setlinebuf||5.007003|
+PerlIO_stderr||5.007003|
+PerlIO_stdin||5.007003|
+PerlIO_stdout||5.007003|
+PerlIO_tell||5.007003|
+PerlIO_unread||5.007003|
+PerlIO_write||5.007003|
+Poison|5.008000||p
+RETVAL|||n
+Renewc|||
+Renew|||
+SAVECLEARSV|||
+SAVECOMPPAD|||
+SAVEPADSV|||
+SAVETMPS|||
+SAVE_DEFSV|5.004050||p
+SPAGAIN|||
+SP|||
+START_EXTERN_C|5.005000||p
+START_MY_CXT|5.007003||p
+STMT_END|||p
+STMT_START|||p
+ST|||
+SVt_IV|||
+SVt_NV|||
+SVt_PVAV|||
+SVt_PVCV|||
+SVt_PVHV|||
+SVt_PVMG|||
+SVt_PV|||
+Safefree|||
+Slab_Alloc|||
+Slab_Free|||
+StructCopy|||
+SvCUR_set|||
+SvCUR|||
+SvEND|||
+SvGETMAGIC|5.004050||p
+SvGROW|||
+SvIOK_UV||5.006000|
+SvIOK_notUV||5.006000|
+SvIOK_off|||
+SvIOK_only_UV||5.006000|
+SvIOK_only|||
+SvIOK_on|||
+SvIOKp|||
+SvIOK|||
+SvIVX|||
+SvIV_nomg|5.009001||p
+SvIV_set|||
+SvIVx|||
+SvIV|||
+SvIsCOW_shared_hash||5.008003|
+SvIsCOW||5.008003|
+SvLEN_set|||
+SvLEN|||
+SvLOCK||5.007003|
+SvMAGIC_set||5.009003|
+SvNIOK_off|||
+SvNIOKp|||
+SvNIOK|||
+SvNOK_off|||
+SvNOK_only|||
+SvNOK_on|||
+SvNOKp|||
+SvNOK|||
+SvNVX|||
+SvNV_set|||
+SvNVx|||
+SvNV|||
+SvOK|||
+SvOOK|||
+SvPOK_off|||
+SvPOK_only_UTF8||5.006000|
+SvPOK_only|||
+SvPOK_on|||
+SvPOKp|||
+SvPOK|||
+SvPVX|||
+SvPV_force_nomg|5.007002||p
+SvPV_force|||
+SvPV_nolen|5.006000||p
+SvPV_nomg|5.007002||p
+SvPV_set|||
+SvPVbyte_force||5.009002|
+SvPVbyte_nolen||5.006000|
+SvPVbytex_force||5.006000|
+SvPVbytex||5.006000|
+SvPVbyte|5.006000||p
+SvPVutf8_force||5.006000|
+SvPVutf8_nolen||5.006000|
+SvPVutf8x_force||5.006000|
+SvPVutf8x||5.006000|
+SvPVutf8||5.006000|
+SvPVx|||
+SvPV|||
+SvREFCNT_dec|||
+SvREFCNT_inc|||
+SvREFCNT|||
+SvROK_off|||
+SvROK_on|||
+SvROK|||
+SvRV_set||5.009003|
+SvRV|||
+SvSETMAGIC|||
+SvSHARE||5.007003|
+SvSTASH_set||5.009003|
+SvSTASH|||
+SvSetMagicSV_nosteal||5.004000|
+SvSetMagicSV||5.004000|
+SvSetSV_nosteal||5.004000|
+SvSetSV|||
+SvTAINTED_off||5.004000|
+SvTAINTED_on||5.004000|
+SvTAINTED||5.004000|
+SvTAINT|||
+SvTRUE|||
+SvTYPE|||
+SvUNLOCK||5.007003|
+SvUOK||5.007001|
+SvUPGRADE|||
+SvUTF8_off||5.006000|
+SvUTF8_on||5.006000|
+SvUTF8||5.006000|
+SvUVXx|5.004000||p
+SvUVX|5.004000||p
+SvUV_nomg|5.009001||p
+SvUV_set||5.009003|
+SvUVx|5.004000||p
+SvUV|5.004000||p
+SvVOK||5.008001|
+THIS|||n
+UNDERBAR|5.009002||p
+UVSIZE|5.006000||p
+UVTYPE|5.006000||p
+UVXf|5.007001||p
+UVof|5.006000||p
+UVuf|5.006000||p
+UVxf|5.006000||p
+XCPT_CATCH|5.009002||p
+XCPT_RETHROW|5.009002||p
+XCPT_TRY_END|5.009002||p
+XCPT_TRY_START|5.009002||p
+XPUSHi|||
+XPUSHmortal|5.009002||p
+XPUSHn|||
+XPUSHp|||
+XPUSHs|||
+XPUSHu|5.004000||p
+XSRETURN_EMPTY|||
+XSRETURN_IV|||
+XSRETURN_NO|||
+XSRETURN_NV|||
+XSRETURN_PV|||
+XSRETURN_UNDEF|||
+XSRETURN_UV|5.008001||p
+XSRETURN_YES|||
+XSRETURN|||
+XST_mIV|||
+XST_mNO|||
+XST_mNV|||
+XST_mPV|||
+XST_mUNDEF|||
+XST_mUV|5.008001||p
+XST_mYES|||
+XS_VERSION_BOOTCHECK|||
+XS_VERSION|||
+XS|||
+ZeroD|5.009002||p
+Zero|||
+_aMY_CXT|5.007003||p
+_pMY_CXT|5.007003||p
+aMY_CXT_|5.007003||p
+aMY_CXT|5.007003||p
+aTHX_|5.006000||p
+aTHX|5.006000||p
+add_data|||
+allocmy|||
+amagic_call|||
+any_dup|||
+ao|||
+append_elem|||
+append_list|||
+apply_attrs_my|||
+apply_attrs_string||5.006001|
+apply_attrs|||
+apply|||
+asIV|||
+asUV|||
+atfork_lock||5.007003|n
+atfork_unlock||5.007003|n
+av_arylen_p||5.009003|
+av_clear|||
+av_delete||5.006000|
+av_exists||5.006000|
+av_extend|||
+av_fake|||
+av_fetch|||
+av_fill|||
+av_len|||
+av_make|||
+av_pop|||
+av_push|||
+av_reify|||
+av_shift|||
+av_store|||
+av_undef|||
+av_unshift|||
+ax|||n
+bad_type|||
+bind_match|||
+block_end|||
+block_gimme||5.004000|
+block_start|||
+boolSV|5.004000||p
+boot_core_PerlIO|||
+boot_core_UNIVERSAL|||
+boot_core_xsutils|||
+bytes_from_utf8||5.007001|
+bytes_to_utf8||5.006001|
+cache_re|||
+call_argv|5.006000||p
+call_atexit||5.006000|
+call_body|||
+call_list_body|||
+call_list||5.004000|
+call_method|5.006000||p
+call_pv|5.006000||p
+call_sv|5.006000||p
+calloc||5.007002|n
+cando|||
+cast_i32||5.006000|
+cast_iv||5.006000|
+cast_ulong||5.006000|
+cast_uv||5.006000|
+check_uni|||
+checkcomma|||
+checkposixcc|||
+ck_anoncode|||
+ck_bitop|||
+ck_concat|||
+ck_defined|||
+ck_delete|||
+ck_die|||
+ck_eof|||
+ck_eval|||
+ck_exec|||
+ck_exists|||
+ck_exit|||
+ck_ftst|||
+ck_fun|||
+ck_glob|||
+ck_grep|||
+ck_index|||
+ck_join|||
+ck_lengthconst|||
+ck_lfun|||
+ck_listiob|||
+ck_match|||
+ck_method|||
+ck_null|||
+ck_open|||
+ck_repeat|||
+ck_require|||
+ck_retarget|||
+ck_return|||
+ck_rfun|||
+ck_rvconst|||
+ck_sassign|||
+ck_select|||
+ck_shift|||
+ck_sort|||
+ck_spair|||
+ck_split|||
+ck_subr|||
+ck_substr|||
+ck_svconst|||
+ck_trunc|||
+ck_unpack|||
+cl_and|||
+cl_anything|||
+cl_init_zero|||
+cl_init|||
+cl_is_anything|||
+cl_or|||
+closest_cop|||
+convert|||
+cop_free|||
+cr_textfilter|||
+croak_nocontext|||vn
+croak|||v
+csighandler||5.007001|n
+custom_op_desc||5.007003|
+custom_op_name||5.007003|
+cv_ckproto|||
+cv_clone|||
+cv_const_sv||5.004000|
+cv_dump|||
+cv_undef|||
+cx_dump||5.005000|
+cx_dup|||
+cxinc|||
+dAXMARK||5.009003|
+dAX|5.007002||p
+dITEMS|5.007002||p
+dMARK|||
+dMY_CXT_SV|5.007003||p
+dMY_CXT|5.007003||p
+dNOOP|5.006000||p
+dORIGMARK|||
+dSP|||
+dTHR|5.004050||p
+dTHXa|5.006000||p
+dTHXoa|5.006000||p
+dTHX|5.006000||p
+dUNDERBAR|5.009002||p
+dXCPT|5.009002||p
+dXSARGS|||
+dXSI32|||
+dXSTARG|5.006000||p
+deb_curcv|||
+deb_nocontext|||vn
+deb_stack_all|||
+deb_stack_n|||
+debop||5.005000|
+debprofdump||5.005000|
+debprof|||
+debstackptrs||5.007003|
+debstack||5.007003|
+deb||5.007003|v
+del_he|||
+del_sv|||
+delimcpy||5.004000|
+depcom|||
+deprecate_old|||
+deprecate|||
+despatch_signals||5.007001|
+die_nocontext|||vn
+die_where|||
+die|||v
+dirp_dup|||
+div128|||
+djSP|||
+do_aexec5|||
+do_aexec|||
+do_aspawn|||
+do_binmode||5.004050|
+do_chomp|||
+do_chop|||
+do_close|||
+do_dump_pad|||
+do_eof|||
+do_exec3|||
+do_execfree|||
+do_exec|||
+do_gv_dump||5.006000|
+do_gvgv_dump||5.006000|
+do_hv_dump||5.006000|
+do_ipcctl|||
+do_ipcget|||
+do_join|||
+do_kv|||
+do_magic_dump||5.006000|
+do_msgrcv|||
+do_msgsnd|||
+do_oddball|||
+do_op_dump||5.006000|
+do_open9||5.006000|
+do_openn||5.007001|
+do_open||5.004000|
+do_pipe|||
+do_pmop_dump||5.006000|
+do_print|||
+do_readline|||
+do_seek|||
+do_semop|||
+do_shmio|||
+do_spawn_nowait|||
+do_spawn|||
+do_sprintf|||
+do_sv_dump||5.006000|
+do_sysseek|||
+do_tell|||
+do_trans_complex_utf8|||
+do_trans_complex|||
+do_trans_count_utf8|||
+do_trans_count|||
+do_trans_simple_utf8|||
+do_trans_simple|||
+do_trans|||
+do_vecget|||
+do_vecset|||
+do_vop|||
+docatch_body|||
+docatch|||
+doeval|||
+dofile|||
+dofindlabel|||
+doform|||
+doing_taint||5.008001|n
+dooneliner|||
+doopen_pm|||
+doparseform|||
+dopoptoeval|||
+dopoptolabel|||
+dopoptoloop|||
+dopoptosub_at|||
+dopoptosub|||
+dounwind|||
+dowantarray|||
+dump_all||5.006000|
+dump_eval||5.006000|
+dump_fds|||
+dump_form||5.006000|
+dump_indent||5.006000|v
+dump_mstats|||
+dump_packsubs||5.006000|
+dump_sub||5.006000|
+dump_vindent||5.006000|
+dumpuntil|||
+dup_attrlist|||
+emulate_eaccess|||
+eval_pv|5.006000||p
+eval_sv|5.006000||p
+expect_number|||
+fbm_compile||5.005000|
+fbm_instr||5.005000|
+fd_on_nosuid_fs|||
+filter_add|||
+filter_del|||
+filter_gets|||
+filter_read|||
+find_beginning|||
+find_byclass|||
+find_in_my_stash|||
+find_runcv|||
+find_rundefsvoffset||5.009002|
+find_script|||
+find_uninit_var|||
+fold_constants|||
+forbid_setid|||
+force_ident|||
+force_list|||
+force_next|||
+force_version|||
+force_word|||
+form_nocontext|||vn
+form||5.004000|v
+fp_dup|||
+fprintf_nocontext|||vn
+free_global_struct|||
+free_tied_hv_pool|||
+free_tmps|||
+gen_constant_list|||
+get_av|5.006000||p
+get_context||5.006000|n
+get_cv|5.006000||p
+get_db_sub|||
+get_debug_opts|||
+get_hash_seed|||
+get_hv|5.006000||p
+get_mstats|||
+get_no_modify|||
+get_num|||
+get_op_descs||5.005000|
+get_op_names||5.005000|
+get_opargs|||
+get_ppaddr||5.006000|
+get_sv|5.006000||p
+get_vtbl||5.005030|
+getcwd_sv||5.007002|
+getenv_len|||
+gp_dup|||
+gp_free|||
+gp_ref|||
+grok_bin|5.007003||p
+grok_hex|5.007003||p
+grok_number|5.007002||p
+grok_numeric_radix|5.007002||p
+grok_oct|5.007003||p
+group_end|||
+gv_AVadd|||
+gv_HVadd|||
+gv_IOadd|||
+gv_autoload4||5.004000|
+gv_check|||
+gv_dump||5.006000|
+gv_efullname3||5.004000|
+gv_efullname4||5.006001|
+gv_efullname|||
+gv_ename|||
+gv_fetchfile|||
+gv_fetchmeth_autoload||5.007003|
+gv_fetchmethod_autoload||5.004000|
+gv_fetchmethod|||
+gv_fetchmeth|||
+gv_fetchpvn_flags||5.009002|
+gv_fetchpv|||
+gv_fetchsv||5.009002|
+gv_fullname3||5.004000|
+gv_fullname4||5.006001|
+gv_fullname|||
+gv_handler||5.007001|
+gv_init_sv|||
+gv_init|||
+gv_share|||
+gv_stashpvn|5.006000||p
+gv_stashpv|||
+gv_stashsv|||
+he_dup|||
+hek_dup|||
+hfreeentries|||
+hsplit|||
+hv_assert||5.009001|
+hv_auxinit|||
+hv_clear_placeholders||5.009001|
+hv_clear|||
+hv_delayfree_ent||5.004000|
+hv_delete_common|||
+hv_delete_ent||5.004000|
+hv_delete|||
+hv_eiter_p||5.009003|
+hv_eiter_set||5.009003|
+hv_exists_ent||5.004000|
+hv_exists|||
+hv_fetch_common|||
+hv_fetch_ent||5.004000|
+hv_fetch|||
+hv_free_ent||5.004000|
+hv_iterinit|||
+hv_iterkeysv||5.004000|
+hv_iterkey|||
+hv_iternext_flags||5.008000|
+hv_iternextsv|||
+hv_iternext|||
+hv_iterval|||
+hv_ksplit||5.004000|
+hv_magic_check|||
+hv_magic|||
+hv_name_set||5.009003|
+hv_notallowed|||
+hv_placeholders_get||5.009003|
+hv_placeholders_p||5.009003|
+hv_placeholders_set||5.009003|
+hv_riter_p||5.009003|
+hv_riter_set||5.009003|
+hv_scalar||5.009001|
+hv_store_ent||5.004000|
+hv_store_flags||5.008000|
+hv_store|||
+hv_undef|||
+ibcmp_locale||5.004000|
+ibcmp_utf8||5.007003|
+ibcmp|||
+incl_perldb|||
+incline|||
+incpush|||
+ingroup|||
+init_argv_symbols|||
+init_debugger|||
+init_global_struct|||
+init_i18nl10n||5.006000|
+init_i18nl14n||5.006000|
+init_ids|||
+init_interp|||
+init_lexer|||
+init_main_stash|||
+init_perllib|||
+init_postdump_symbols|||
+init_predump_symbols|||
+init_stacks||5.005000|
+init_tm||5.007002|
+instr|||
+intro_my|||
+intuit_method|||
+intuit_more|||
+invert|||
+io_close|||
+isALNUM|||
+isALPHA|||
+isDIGIT|||
+isLOWER|||
+isSPACE|||
+isUPPER|||
+is_an_int|||
+is_gv_magical_sv|||
+is_gv_magical|||
+is_handle_constructor|||
+is_list_assignment|||
+is_lvalue_sub||5.007001|
+is_uni_alnum_lc||5.006000|
+is_uni_alnumc_lc||5.006000|
+is_uni_alnumc||5.006000|
+is_uni_alnum||5.006000|
+is_uni_alpha_lc||5.006000|
+is_uni_alpha||5.006000|
+is_uni_ascii_lc||5.006000|
+is_uni_ascii||5.006000|
+is_uni_cntrl_lc||5.006000|
+is_uni_cntrl||5.006000|
+is_uni_digit_lc||5.006000|
+is_uni_digit||5.006000|
+is_uni_graph_lc||5.006000|
+is_uni_graph||5.006000|
+is_uni_idfirst_lc||5.006000|
+is_uni_idfirst||5.006000|
+is_uni_lower_lc||5.006000|
+is_uni_lower||5.006000|
+is_uni_print_lc||5.006000|
+is_uni_print||5.006000|
+is_uni_punct_lc||5.006000|
+is_uni_punct||5.006000|
+is_uni_space_lc||5.006000|
+is_uni_space||5.006000|
+is_uni_upper_lc||5.006000|
+is_uni_upper||5.006000|
+is_uni_xdigit_lc||5.006000|
+is_uni_xdigit||5.006000|
+is_utf8_alnumc||5.006000|
+is_utf8_alnum||5.006000|
+is_utf8_alpha||5.006000|
+is_utf8_ascii||5.006000|
+is_utf8_char_slow|||
+is_utf8_char||5.006000|
+is_utf8_cntrl||5.006000|
+is_utf8_digit||5.006000|
+is_utf8_graph||5.006000|
+is_utf8_idcont||5.008000|
+is_utf8_idfirst||5.006000|
+is_utf8_lower||5.006000|
+is_utf8_mark||5.006000|
+is_utf8_print||5.006000|
+is_utf8_punct||5.006000|
+is_utf8_space||5.006000|
+is_utf8_string_loclen||5.009003|
+is_utf8_string_loc||5.008001|
+is_utf8_string||5.006001|
+is_utf8_upper||5.006000|
+is_utf8_xdigit||5.006000|
+isa_lookup|||
+items|||n
+ix|||n
+jmaybe|||
+keyword|||
+leave_scope|||
+lex_end|||
+lex_start|||
+linklist|||
+listkids|||
+list|||
+load_module_nocontext|||vn
+load_module||5.006000|v
+localize|||
+looks_like_number|||
+lop|||
+mPUSHi|5.009002||p
+mPUSHn|5.009002||p
+mPUSHp|5.009002||p
+mPUSHu|5.009002||p
+mXPUSHi|5.009002||p
+mXPUSHn|5.009002||p
+mXPUSHp|5.009002||p
+mXPUSHu|5.009002||p
+magic_clear_all_env|||
+magic_clearenv|||
+magic_clearpack|||
+magic_clearsig|||
+magic_dump||5.006000|
+magic_existspack|||
+magic_freearylen_p|||
+magic_freeovrld|||
+magic_freeregexp|||
+magic_getarylen|||
+magic_getdefelem|||
+magic_getglob|||
+magic_getnkeys|||
+magic_getpack|||
+magic_getpos|||
+magic_getsig|||
+magic_getsubstr|||
+magic_gettaint|||
+magic_getuvar|||
+magic_getvec|||
+magic_get|||
+magic_killbackrefs|||
+magic_len|||
+magic_methcall|||
+magic_methpack|||
+magic_nextpack|||
+magic_regdata_cnt|||
+magic_regdatum_get|||
+magic_regdatum_set|||
+magic_scalarpack|||
+magic_set_all_env|||
+magic_setamagic|||
+magic_setarylen|||
+magic_setbm|||
+magic_setcollxfrm|||
+magic_setdbline|||
+magic_setdefelem|||
+magic_setenv|||
+magic_setfm|||
+magic_setglob|||
+magic_setisa|||
+magic_setmglob|||
+magic_setnkeys|||
+magic_setpack|||
+magic_setpos|||
+magic_setregexp|||
+magic_setsig|||
+magic_setsubstr|||
+magic_settaint|||
+magic_setutf8|||
+magic_setuvar|||
+magic_setvec|||
+magic_set|||
+magic_sizepack|||
+magic_wipepack|||
+magicname|||
+make_trie|||
+malloced_size|||n
+malloc||5.007002|n
+markstack_grow|||
+measure_struct|||
+memEQ|5.004000||p
+memNE|5.004000||p
+mem_collxfrm|||
+mess_alloc|||
+mess_nocontext|||vn
+mess||5.006000|v
+method_common|||
+mfree||5.007002|n
+mg_clear|||
+mg_copy|||
+mg_dup|||
+mg_find|||
+mg_free|||
+mg_get|||
+mg_length||5.005000|
+mg_localize|||
+mg_magical|||
+mg_set|||
+mg_size||5.005000|
+mini_mktime||5.007002|
+missingterm|||
+mode_from_discipline|||
+modkids|||
+mod|||
+moreswitches|||
+mul128|||
+mulexp10|||n
+my_atof2||5.007002|
+my_atof||5.006000|
+my_attrs|||
+my_bcopy|||n
+my_betoh16|||n
+my_betoh32|||n
+my_betoh64|||n
+my_betohi|||n
+my_betohl|||n
+my_betohs|||n
+my_bzero|||n
+my_chsize|||
+my_exit_jump|||
+my_exit|||
+my_failure_exit||5.004000|
+my_fflush_all||5.006000|
+my_fork||5.007003|n
+my_htobe16|||n
+my_htobe32|||n
+my_htobe64|||n
+my_htobei|||n
+my_htobel|||n
+my_htobes|||n
+my_htole16|||n
+my_htole32|||n
+my_htole64|||n
+my_htolei|||n
+my_htolel|||n
+my_htoles|||n
+my_htonl|||
+my_kid|||
+my_letoh16|||n
+my_letoh32|||n
+my_letoh64|||n
+my_letohi|||n
+my_letohl|||n
+my_letohs|||n
+my_lstat|||
+my_memcmp||5.004000|n
+my_memset|||n
+my_ntohl|||
+my_pclose||5.004000|
+my_popen_list||5.007001|
+my_popen||5.004000|
+my_setenv|||
+my_socketpair||5.007003|n
+my_stat|||
+my_strftime||5.007002|
+my_swabn|||n
+my_swap|||
+my_unexec|||
+my|||
+newANONATTRSUB||5.006000|
+newANONHASH|||
+newANONLIST|||
+newANONSUB|||
+newASSIGNOP|||
+newATTRSUB||5.006000|
+newAVREF|||
+newAV|||
+newBINOP|||
+newCONDOP|||
+newCONSTSUB|5.006000||p
+newCVREF|||
+newDEFSVOP|||
+newFORM|||
+newFOROP|||
+newGVOP|||
+newGVREF|||
+newGVgen|||
+newHVREF|||
+newHVhv||5.005000|
+newHV|||
+newIO|||
+newLISTOP|||
+newLOGOP|||
+newLOOPEX|||
+newLOOPOP|||
+newMYSUB||5.006000|
+newNULLLIST|||
+newOP|||
+newPADOP||5.006000|
+newPMOP|||
+newPROG|||
+newPVOP|||
+newRANGE|||
+newRV_inc|5.004000||p
+newRV_noinc|5.006000||p
+newRV|||
+newSLICEOP|||
+newSTATEOP|||
+newSUB|||
+newSVOP|||
+newSVREF|||
+newSVhek||5.009003|
+newSViv|||
+newSVnv|||
+newSVpvf_nocontext|||vn
+newSVpvf||5.004000|v
+newSVpvn_share||5.007001|
+newSVpvn|5.006000||p
+newSVpv|||
+newSVrv|||
+newSVsv|||
+newSVuv|5.006000||p
+newSV|||
+newUNOP|||
+newWHILEOP||5.009003|
+newXSproto||5.006000|
+newXS||5.006000|
+new_collate||5.006000|
+new_constant|||
+new_ctype||5.006000|
+new_he|||
+new_logop|||
+new_numeric||5.006000|
+new_stackinfo||5.005000|
+new_version||5.009000|
+next_symbol|||
+nextargv|||
+nextchar|||
+ninstr|||
+no_bareword_allowed|||
+no_fh_allowed|||
+no_op|||
+not_a_number|||
+nothreadhook||5.008000|
+nuke_stacks|||
+num_overflow|||n
+oopsAV|||
+oopsCV|||
+oopsHV|||
+op_clear|||
+op_const_sv|||
+op_dump||5.006000|
+op_free|||
+op_null||5.007002|
+op_refcnt_lock||5.009002|
+op_refcnt_unlock||5.009002|
+open_script|||
+pMY_CXT_|5.007003||p
+pMY_CXT|5.007003||p
+pTHX_|5.006000||p
+pTHX|5.006000||p
+pack_cat||5.007003|
+pack_rec|||
+package|||
+packlist||5.008001|
+pad_add_anon|||
+pad_add_name|||
+pad_alloc|||
+pad_block_start|||
+pad_check_dup|||
+pad_compname_type|||
+pad_findlex|||
+pad_findmy|||
+pad_fixup_inner_anons|||
+pad_free|||
+pad_leavemy|||
+pad_new|||
+pad_push|||
+pad_reset|||
+pad_setsv|||
+pad_sv|||
+pad_swipe|||
+pad_tidy|||
+pad_undef|||
+parse_body|||
+parse_unicode_opts|||
+path_is_absolute|||
+peep|||
+pending_ident|||
+perl_alloc_using|||n
+perl_alloc|||n
+perl_clone_using|||n
+perl_clone|||n
+perl_construct|||n
+perl_destruct||5.007003|n
+perl_free|||n
+perl_parse||5.006000|n
+perl_run|||n
+pidgone|||
+pmflag|||
+pmop_dump||5.006000|
+pmruntime|||
+pmtrans|||
+pop_scope|||
+pregcomp|||
+pregexec|||
+pregfree|||
+prepend_elem|||
+printf_nocontext|||vn
+ptr_table_clear|||
+ptr_table_fetch|||
+ptr_table_free|||
+ptr_table_new|||
+ptr_table_split|||
+ptr_table_store|||
+push_scope|||
+put_byte|||
+pv_display||5.006000|
+pv_uni_display||5.007003|
+qerror|||
+re_croak2|||
+re_dup|||
+re_intuit_start||5.006000|
+re_intuit_string||5.006000|
+realloc||5.007002|n
+reentrant_free|||
+reentrant_init|||
+reentrant_retry|||vn
+reentrant_size|||
+refkids|||
+refto|||
+ref|||
+reg_node|||
+reganode|||
+regatom|||
+regbranch|||
+regclass_swash||5.007003|
+regclass|||
+regcp_set_to|||
+regcppop|||
+regcppush|||
+regcurly|||
+regdump||5.005000|
+regexec_flags||5.005000|
+reghop3|||
+reghopmaybe3|||
+reghopmaybe|||
+reghop|||
+reginclass|||
+reginitcolors||5.006000|
+reginsert|||
+regmatch|||
+regnext||5.005000|
+regoptail|||
+regpiece|||
+regpposixcc|||
+regprop|||
+regrepeat_hard|||
+regrepeat|||
+regtail|||
+regtry|||
+reguni|||
+regwhite|||
+reg|||
+repeatcpy|||
+report_evil_fh|||
+report_uninit|||
+require_errno|||
+require_pv||5.006000|
+rninstr|||
+rsignal_restore|||
+rsignal_save|||
+rsignal_state||5.004000|
+rsignal||5.004000|
+run_body|||
+runops_debug||5.005000|
+runops_standard||5.005000|
+rvpv_dup|||
+rxres_free|||
+rxres_restore|||
+rxres_save|||
+safesyscalloc||5.006000|n
+safesysfree||5.006000|n
+safesysmalloc||5.006000|n
+safesysrealloc||5.006000|n
+same_dirent|||
+save_I16||5.004000|
+save_I32|||
+save_I8||5.006000|
+save_aelem||5.004050|
+save_alloc||5.006000|
+save_aptr|||
+save_ary|||
+save_bool||5.008001|
+save_clearsv|||
+save_delete|||
+save_destructor_x||5.006000|
+save_destructor||5.006000|
+save_freeop|||
+save_freepv|||
+save_freesv|||
+save_generic_pvref||5.006001|
+save_generic_svref||5.005030|
+save_gp||5.004000|
+save_hash|||
+save_hek_flags|||
+save_helem||5.004050|
+save_hints||5.005000|
+save_hptr|||
+save_int|||
+save_item|||
+save_iv||5.005000|
+save_lines|||
+save_list|||
+save_long|||
+save_magic|||
+save_mortalizesv||5.007001|
+save_nogv|||
+save_op|||
+save_padsv||5.007001|
+save_pptr|||
+save_re_context||5.006000|
+save_scalar_at|||
+save_scalar|||
+save_set_svflags||5.009000|
+save_shared_pvref||5.007003|
+save_sptr|||
+save_svref|||
+save_threadsv||5.005000|
+save_vptr||5.006000|
+savepvn|||
+savepv|||
+savesharedpv||5.007003|
+savestack_grow_cnt||5.008001|
+savestack_grow|||
+savesvpv||5.009002|
+sawparens|||
+scalar_mod_type|||
+scalarboolean|||
+scalarkids|||
+scalarseq|||
+scalarvoid|||
+scalar|||
+scan_bin||5.006000|
+scan_commit|||
+scan_const|||
+scan_formline|||
+scan_heredoc|||
+scan_hex|||
+scan_ident|||
+scan_inputsymbol|||
+scan_num||5.007001|
+scan_oct|||
+scan_pat|||
+scan_str|||
+scan_subst|||
+scan_trans|||
+scan_version||5.009001|
+scan_vstring||5.008001|
+scan_word|||
+scope|||
+screaminstr||5.005000|
+seed|||
+set_context||5.006000|n
+set_csh|||
+set_numeric_local||5.006000|
+set_numeric_radix||5.006000|
+set_numeric_standard||5.006000|
+setdefout|||
+setenv_getix|||
+share_hek_flags|||
+share_hek|||
+si_dup|||
+sighandler|||n
+simplify_sort|||
+skipspace|||
+sortsv||5.007003|
+ss_dup|||
+stack_grow|||
+start_glob|||
+start_subparse||5.004000|
+stashpv_hvname_match||5.009003|
+stdize_locale|||
+strEQ|||
+strGE|||
+strGT|||
+strLE|||
+strLT|||
+strNE|||
+str_to_version||5.006000|
+strnEQ|||
+strnNE|||
+study_chunk|||
+sub_crush_depth|||
+sublex_done|||
+sublex_push|||
+sublex_start|||
+sv_2bool|||
+sv_2cv|||
+sv_2io|||
+sv_2iuv_non_preserve|||
+sv_2iv_flags||5.009001|
+sv_2iv|||
+sv_2mortal|||
+sv_2nv|||
+sv_2pv_flags||5.007002|
+sv_2pv_nolen|5.006000||p
+sv_2pvbyte_nolen|||
+sv_2pvbyte|5.006000||p
+sv_2pvutf8_nolen||5.006000|
+sv_2pvutf8||5.006000|
+sv_2pv|||
+sv_2uv_flags||5.009001|
+sv_2uv|5.004000||p
+sv_add_arena|||
+sv_add_backref|||
+sv_backoff|||
+sv_bless|||
+sv_cat_decode||5.008001|
+sv_catpv_mg|5.006000||p
+sv_catpvf_mg_nocontext|||pvn
+sv_catpvf_mg|5.006000|5.004000|pv
+sv_catpvf_nocontext|||vn
+sv_catpvf||5.004000|v
+sv_catpvn_flags||5.007002|
+sv_catpvn_mg|5.006000||p
+sv_catpvn_nomg|5.007002||p
+sv_catpvn|||
+sv_catpv|||
+sv_catsv_flags||5.007002|
+sv_catsv_mg|5.006000||p
+sv_catsv_nomg|5.007002||p
+sv_catsv|||
+sv_chop|||
+sv_clean_all|||
+sv_clean_objs|||
+sv_clear|||
+sv_cmp_locale||5.004000|
+sv_cmp|||
+sv_collxfrm|||
+sv_compile_2op||5.008001|
+sv_copypv||5.007003|
+sv_dec|||
+sv_del_backref|||
+sv_derived_from||5.004000|
+sv_dump|||
+sv_dup|||
+sv_eq|||
+sv_force_normal_flags||5.007001|
+sv_force_normal||5.006000|
+sv_free2|||
+sv_free_arenas|||
+sv_free|||
+sv_gets||5.004000|
+sv_grow|||
+sv_inc|||
+sv_insert|||
+sv_isa|||
+sv_isobject|||
+sv_iv||5.005000|
+sv_len_utf8||5.006000|
+sv_len|||
+sv_magicext||5.007003|
+sv_magic|||
+sv_mortalcopy|||
+sv_newmortal|||
+sv_newref|||
+sv_nolocking||5.007003|
+sv_nosharing||5.007003|
+sv_nounlocking||5.007003|
+sv_nv||5.005000|
+sv_peek||5.005000|
+sv_pos_b2u||5.006000|
+sv_pos_u2b||5.006000|
+sv_pvbyten_force||5.006000|
+sv_pvbyten||5.006000|
+sv_pvbyte||5.006000|
+sv_pvn_force_flags||5.007002|
+sv_pvn_force|||p
+sv_pvn_nomg|5.007003||p
+sv_pvn|5.006000||p
+sv_pvutf8n_force||5.006000|
+sv_pvutf8n||5.006000|
+sv_pvutf8||5.006000|
+sv_pv||5.006000|
+sv_recode_to_utf8||5.007003|
+sv_reftype|||
+sv_release_COW|||
+sv_release_IVX|||
+sv_replace|||
+sv_report_used|||
+sv_reset|||
+sv_rvweaken||5.006000|
+sv_setiv_mg|5.006000||p
+sv_setiv|||
+sv_setnv_mg|5.006000||p
+sv_setnv|||
+sv_setpv_mg|5.006000||p
+sv_setpvf_mg_nocontext|||pvn
+sv_setpvf_mg|5.006000|5.004000|pv
+sv_setpvf_nocontext|||vn
+sv_setpvf||5.004000|v
+sv_setpviv_mg||5.008001|
+sv_setpviv||5.008001|
+sv_setpvn_mg|5.006000||p
+sv_setpvn|||
+sv_setpv|||
+sv_setref_iv|||
+sv_setref_nv|||
+sv_setref_pvn|||
+sv_setref_pv|||
+sv_setref_uv||5.007001|
+sv_setsv_cow|||
+sv_setsv_flags||5.007002|
+sv_setsv_mg|5.006000||p
+sv_setsv_nomg|5.007002||p
+sv_setsv|||
+sv_setuv_mg|5.006000||p
+sv_setuv|5.006000||p
+sv_tainted||5.004000|
+sv_taint||5.004000|
+sv_true||5.005000|
+sv_unglob|||
+sv_uni_display||5.007003|
+sv_unmagic|||
+sv_unref_flags||5.007001|
+sv_unref|||
+sv_untaint||5.004000|
+sv_upgrade|||
+sv_usepvn_mg|5.006000||p
+sv_usepvn|||
+sv_utf8_decode||5.006000|
+sv_utf8_downgrade||5.006000|
+sv_utf8_encode||5.006000|
+sv_utf8_upgrade_flags||5.007002|
+sv_utf8_upgrade||5.007001|
+sv_uv|5.006000||p
+sv_vcatpvf_mg|5.006000|5.004000|p
+sv_vcatpvfn||5.004000|
+sv_vcatpvf|5.006000|5.004000|p
+sv_vsetpvf_mg|5.006000|5.004000|p
+sv_vsetpvfn||5.004000|
+sv_vsetpvf|5.006000|5.004000|p
+svtype|||
+swallow_bom|||
+swash_fetch||5.007002|
+swash_init||5.006000|
+sys_intern_clear|||
+sys_intern_dup|||
+sys_intern_init|||
+taint_env|||
+taint_proper|||
+tmps_grow||5.006000|
+toLOWER|||
+toUPPER|||
+to_byte_substr|||
+to_uni_fold||5.007003|
+to_uni_lower_lc||5.006000|
+to_uni_lower||5.007003|
+to_uni_title_lc||5.006000|
+to_uni_title||5.007003|
+to_uni_upper_lc||5.006000|
+to_uni_upper||5.007003|
+to_utf8_case||5.007003|
+to_utf8_fold||5.007003|
+to_utf8_lower||5.007003|
+to_utf8_substr|||
+to_utf8_title||5.007003|
+to_utf8_upper||5.007003|
+tokeq|||
+tokereport|||
+too_few_arguments|||
+too_many_arguments|||
+unlnk|||
+unpack_rec|||
+unpack_str||5.007003|
+unpackstring||5.008001|
+unshare_hek_or_pvn|||
+unshare_hek|||
+unsharepvn||5.004000|
+upg_version||5.009000|
+usage|||
+utf16_textfilter|||
+utf16_to_utf8_reversed||5.006001|
+utf16_to_utf8||5.006001|
+utf16rev_textfilter|||
+utf8_distance||5.006000|
+utf8_hop||5.006000|
+utf8_length||5.007001|
+utf8_mg_pos_init|||
+utf8_mg_pos|||
+utf8_to_bytes||5.006001|
+utf8_to_uvchr||5.007001|
+utf8_to_uvuni||5.007001|
+utf8n_to_uvchr||5.007001|
+utf8n_to_uvuni||5.007001|
+utilize|||
+uvchr_to_utf8_flags||5.007003|
+uvchr_to_utf8||5.007001|
+uvuni_to_utf8_flags||5.007003|
+uvuni_to_utf8||5.007001|
+validate_suid|||
+varname|||
+vcmp||5.009000|
+vcroak||5.006000|
+vdeb||5.007003|
+vdie|||
+vform||5.006000|
+visit|||
+vivify_defelem|||
+vivify_ref|||
+vload_module||5.006000|
+vmess||5.006000|
+vnewSVpvf|5.006000|5.004000|p
+vnormal||5.009002|
+vnumify||5.009000|
+vstringify||5.009000|
+vwarner||5.006000|
+vwarn||5.006000|
+wait4pid|||
+warn_nocontext|||vn
+warner_nocontext|||vn
+warner||5.006000|v
+warn|||v
+watch|||
+whichsig|||
+write_to_stderr|||
+yyerror|||
+yylex|||
+yyparse|||
+yywarn|||
+);
+
+if (exists $opt{'list-unsupported'}) {
+  my $f;
+  for $f (sort { lc $a cmp lc $b } keys %API) {
+    next unless $API{$f}{todo};
+    print "$f ", '.'x(40-length($f)), " ", format_version($API{$f}{todo}), "\n";
+  }
+  exit 0;
+}
+
+# Scan for possible replacement candidates
+
+my(%replace, %need, %hints, %depends);
+my $replace = 0;
+my $hint = '';
+
+while (<DATA>) {
+  if ($hint) {
+    if (m{^\s*\*\s(.*?)\s*$}) {
+      $hints{$hint} ||= '';  # suppress warning with older perls
+      $hints{$hint} .= "$1\n";
+    }
+    else {
+      $hint = '';
+    }
+  }
+  $hint = $1 if m{^\s*$rccs\sHint:\s+(\w+)\s*$};
+
+  $replace     = $1 if m{^\s*$rccs\s+Replace:\s+(\d+)\s+$rcce\s*$};
+  $replace{$2} = $1 if $replace and m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(\w+)};
+  $replace{$2} = $1 if m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(\w+).*$rccs\s+Replace\s+$rcce};
+  $replace{$1} = $2 if m{^\s*$rccs\s+Replace (\w+) with (\w+)\s+$rcce\s*$};
+
+  if (m{^\s*$rccs\s+(\w+)\s+depends\s+on\s+(\w+(\s*,\s*\w+)*)\s+$rcce\s*$}) {
+    push @{$depends{$1}}, map { s/\s+//g; $_ } split /,/, $2;
+  }
+
+  $need{$1} = 1 if m{^#if\s+defined\(NEED_(\w+)(?:_GLOBAL)?\)};
+}
+
+if (exists $opt{'api-info'}) {
+  my $f;
+  my $count = 0;
+  my $match = $opt{'api-info'} =~ m!^/(.*)/$! ? $1 : "^\Q$opt{'api-info'}\E\$";
+  for $f (sort { lc $a cmp lc $b } keys %API) {
+    next unless $f =~ /$match/;
+    print "\n=== $f ===\n\n";
+    my $info = 0;
+    if ($API{$f}{base} || $API{$f}{todo}) {
+      my $base = format_version($API{$f}{base} || $API{$f}{todo});
+      print "Supported at least starting from perl-$base.\n";
+      $info++;
+    }
+    if ($API{$f}{provided}) {
+      my $todo = $API{$f}{todo} ? format_version($API{$f}{todo}) : "5.003";
+      print "Support by $ppport provided back to perl-$todo.\n";
+      print "Support needs to be explicitly requested by NEED_$f.\n" if exists $need{$f};
+      print "Depends on: ", join(', ', @{$depends{$f}}), ".\n" if exists $depends{$f};
+      print "$hints{$f}" if exists $hints{$f};
+      $info++;
+    }
+    unless ($info) {
+      print "No portability information available.\n";
+    }
+    $count++;
+  }
+  if ($count > 0) {
+    print "\n";
+  }
+  else {
+    print "Found no API matching '$opt{'api-info'}'.\n";
+  }
+  exit 0;
+}
+
+if (exists $opt{'list-provided'}) {
+  my $f;
+  for $f (sort { lc $a cmp lc $b } keys %API) {
+    next unless $API{$f}{provided};
+    my @flags;
+    push @flags, 'explicit' if exists $need{$f};
+    push @flags, 'depend'   if exists $depends{$f};
+    push @flags, 'hint'     if exists $hints{$f};
+    my $flags = @flags ? '  ['.join(', ', @flags).']' : '';
+    print "$f$flags\n";
+  }
+  exit 0;
+}
+
+my @files;
+my @srcext = qw( xs c h cc cpp );
+my $srcext = join '|', @srcext;
+
+if (@ARGV) {
+  my %seen;
+  @files = grep { -f && !exists $seen{$_} } map { glob $_ } @ARGV;
+}
+else {
+  eval {
+    require File::Find;
+    File::Find::find(sub {
+      $File::Find::name =~ /\.($srcext)$/i
+          and push @files, $File::Find::name;
+    }, '.');
+  };
+  if ($@) {
+    @files = map { glob "*.$_" } @srcext;
+  }
+}
+
+if (!@ARGV || $opt{filter}) {
+  my(@in, @out);
+  my %xsc = map { /(.*)\.xs$/ ? ("$1.c" => 1, "$1.cc" => 1) : () } @files;
+  for (@files) {
+    my $out = exists $xsc{$_} || /\b\Q$ppport\E$/i || !/\.($srcext)$/i;
+    push @{ $out ? \@out : \@in }, $_;
+  }
+  if (@ARGV && @out) {
+    warning("Skipping the following files (use --nofilter to avoid this):\n| ", join "\n| ", @out);
+  }
+  @files = @in;
+}
+
+unless (@files) {
+  die "No input files given!\n";
+}
+
+my(%files, %global, %revreplace);
+%revreplace = reverse %replace;
+my $filename;
+my $patch_opened = 0;
+
+for $filename (@files) {
+  unless (open IN, "<$filename") {
+    warn "Unable to read from $filename: $!\n";
+    next;
+  }
+
+  info("Scanning $filename ...");
+
+  my $c = do { local $/; <IN> };
+  close IN;
+
+  my %file = (orig => $c, changes => 0);
+
+  # temporarily remove C comments from the code
+  my @ccom;
+  $c =~ s{
+    (
+        [^"'/]+
+      |
+        (?:"[^"\\]*(?:\\.[^"\\]*)*" [^"'/]*)+
+      |
+        (?:'[^'\\]*(?:\\.[^'\\]*)*' [^"'/]*)+
+    )
+  |
+    (/ (?:
+        \*[^*]*\*+(?:[^$ccs][^*]*\*+)* /
+        |
+        /[^\r\n]*
+      ))
+  }{
+    defined $2 and push @ccom, $2;
+    defined $1 ? $1 : "$ccs$#ccom$cce";
+  }egsx;
+
+  $file{ccom} = \@ccom;
+  $file{code} = $c;
+  $file{has_inc_ppport} = ($c =~ /#.*include.*\Q$ppport\E/);
+
+  my $func;
+
+  for $func (keys %API) {
+    my $match = $func;
+    $match .= "|$revreplace{$func}" if exists $revreplace{$func};
+    if ($c =~ /\b(?:Perl_)?($match)\b/) {
+      $file{uses_replace}{$1}++ if exists $revreplace{$func} && $1 eq $revreplace{$func};
+      $file{uses_Perl}{$func}++ if $c =~ /\bPerl_$func\b/;
+      if (exists $API{$func}{provided}) {
+        if (!exists $API{$func}{base} || $API{$func}{base} > $opt{'compat-version'}) {
+          $file{uses}{$func}++;
+          my @deps = rec_depend($func);
+          if (@deps) {
+            $file{uses_deps}{$func} = \@deps;
+            for (@deps) {
+              $file{uses}{$_} = 0 unless exists $file{uses}{$_};
+            }
+          }
+          for ($func, @deps) {
+            if (exists $need{$_}) {
+              $file{needs}{$_} = 'static';
+            }
+          }
+        }
+      }
+      if (exists $API{$func}{todo} && $API{$func}{todo} > $opt{'compat-version'}) {
+        if ($c =~ /\b$func\b/) {
+          $file{uses_todo}{$func}++;
+        }
+      }
+    }
+  }
+
+  while ($c =~ /^$HS*#$HS*define$HS+(NEED_(\w+?)(_GLOBAL)?)\b/mg) {
+    if (exists $need{$2}) {
+      $file{defined $3 ? 'needed_global' : 'needed_static'}{$2}++;
+    }
+    else {
+      warning("Possibly wrong #define $1 in $filename");
+    }
+  }
+
+  for (qw(uses needs uses_todo needed_global needed_static)) {
+    for $func (keys %{$file{$_}}) {
+      push @{$global{$_}{$func}}, $filename;
+    }
+  }
+
+  $files{$filename} = \%file;
+}
+
+# Globally resolve NEED_'s
+my $need;
+for $need (keys %{$global{needs}}) {
+  if (@{$global{needs}{$need}} > 1) {
+    my @targets = @{$global{needs}{$need}};
+    my @t = grep $files{$_}{needed_global}{$need}, @targets;
+    @targets = @t if @t;
+    @t = grep /\.xs$/i, @targets;
+    @targets = @t if @t;
+    my $target = shift @targets;
+    $files{$target}{needs}{$need} = 'global';
+    for (@{$global{needs}{$need}}) {
+      $files{$_}{needs}{$need} = 'extern' if $_ ne $target;
+    }
+  }
+}
+
+for $filename (@files) {
+  exists $files{$filename} or next;
+
+  info("=== Analyzing $filename ===");
+
+  my %file = %{$files{$filename}};
+  my $func;
+  my $c = $file{code};
+
+  for $func (sort keys %{$file{uses_Perl}}) {
+    if ($API{$func}{varargs}) {
+      my $changes = ($c =~ s{\b(Perl_$func\s*\(\s*)(?!aTHX_?)(\)|[^\s)]*\))}
+                            { $1 . ($2 eq ')' ? 'aTHX' : 'aTHX_ ') . $2 }ge);
+      if ($changes) {
+        warning("Doesn't pass interpreter argument aTHX to Perl_$func");
+        $file{changes} += $changes;
+      }
+    }
+    else {
+      warning("Uses Perl_$func instead of $func");
+      $file{changes} += ($c =~ s{\bPerl_$func(\s*)\((\s*aTHX_?)?\s*}
+                                {$func$1(}g);
+    }
+  }
+
+  for $func (sort keys %{$file{uses_replace}}) {
+    warning("Uses $func instead of $replace{$func}");
+    $file{changes} += ($c =~ s/\b$func\b/$replace{$func}/g);
+  }
+
+  for $func (sort keys %{$file{uses}}) {
+    next unless $file{uses}{$func};   # if it's only a dependency
+    if (exists $file{uses_deps}{$func}) {
+      diag("Uses $func, which depends on ", join(', ', @{$file{uses_deps}{$func}}));
+    }
+    elsif (exists $replace{$func}) {
+      warning("Uses $func instead of $replace{$func}");
+      $file{changes} += ($c =~ s/\b$func\b/$replace{$func}/g);
+    }
+    else {
+      diag("Uses $func");
+    }
+    hint($func);
+  }
+
+  for $func (sort keys %{$file{uses_todo}}) {
+    warning("Uses $func, which may not be portable below perl ",
+            format_version($API{$func}{todo}));
+  }
+
+  for $func (sort keys %{$file{needed_static}}) {
+    my $message = '';
+    if (not exists $file{uses}{$func}) {
+      $message = "No need to define NEED_$func if $func is never used";
+    }
+    elsif (exists $file{needs}{$func} && $file{needs}{$func} ne 'static') {
+      $message = "No need to define NEED_$func when already needed globally";
+    }
+    if ($message) {
+      diag($message);
+      $file{changes} += ($c =~ s/^$HS*#$HS*define$HS+NEED_$func\b.*$LF//mg);
+    }
+  }
+
+  for $func (sort keys %{$file{needed_global}}) {
+    my $message = '';
+    if (not exists $global{uses}{$func}) {
+      $message = "No need to define NEED_${func}_GLOBAL if $func is never used";
+    }
+    elsif (exists $file{needs}{$func}) {
+      if ($file{needs}{$func} eq 'extern') {
+        $message = "No need to define NEED_${func}_GLOBAL when already needed globally";
+      }
+      elsif ($file{needs}{$func} eq 'static') {
+        $message = "No need to define NEED_${func}_GLOBAL when only used in this file";
+      }
+    }
+    if ($message) {
+      diag($message);
+      $file{changes} += ($c =~ s/^$HS*#$HS*define$HS+NEED_${func}_GLOBAL\b.*$LF//mg);
+    }
+  }
+
+  $file{needs_inc_ppport} = keys %{$file{uses}};
+
+  if ($file{needs_inc_ppport}) {
+    my $pp = '';
+
+    for $func (sort keys %{$file{needs}}) {
+      my $type = $file{needs}{$func};
+      next if $type eq 'extern';
+      my $suffix = $type eq 'global' ? '_GLOBAL' : '';
+      unless (exists $file{"needed_$type"}{$func}) {
+        if ($type eq 'global') {
+          diag("Files [@{$global{needs}{$func}}] need $func, adding global request");
+        }
+        else {
+          diag("File needs $func, adding static request");
+        }
+        $pp .= "#define NEED_$func$suffix\n";
+      }
+    }
+
+    if ($pp && ($c =~ s/^(?=$HS*#$HS*define$HS+NEED_\w+)/$pp/m)) {
+      $pp = '';
+      $file{changes}++;
+    }
+
+    unless ($file{has_inc_ppport}) {
+      diag("Needs to include '$ppport'");
+      $pp .= qq(#include "$ppport"\n)
+    }
+
+    if ($pp) {
+      $file{changes} += ($c =~ s/^($HS*#$HS*define$HS+NEED_\w+.*?)^/$1$pp/ms)
+                     || ($c =~ s/^(?=$HS*#$HS*include.*\Q$ppport\E)/$pp/m)
+                     || ($c =~ s/^($HS*#$HS*include.*XSUB.*\s*?)^/$1$pp/m)
+                     || ($c =~ s/^/$pp/);
+    }
+  }
+  else {
+    if ($file{has_inc_ppport}) {
+      diag("No need to include '$ppport'");
+      $file{changes} += ($c =~ s/^$HS*?#$HS*include.*\Q$ppport\E.*?$LF//m);
+    }
+  }
+
+  # put back in our C comments
+  my $ix;
+  my $cppc = 0;
+  my @ccom = @{$file{ccom}};
+  for $ix (0 .. $#ccom) {
+    if (!$opt{cplusplus} && $ccom[$ix] =~ s!^//!!) {
+      $cppc++;
+      $file{changes} += $c =~ s/$rccs$ix$rcce/$ccs$ccom[$ix] $cce/;
+    }
+    else {
+      $c =~ s/$rccs$ix$rcce/$ccom[$ix]/;
+    }
+  }
+
+  if ($cppc) {
+    my $s = $cppc != 1 ? 's' : '';
+    warning("Uses $cppc C++ style comment$s, which is not portable");
+  }
+
+  if ($file{changes}) {
+    if (exists $opt{copy}) {
+      my $newfile = "$filename$opt{copy}";
+      if (-e $newfile) {
+        error("'$newfile' already exists, refusing to write copy of '$filename'");
+      }
+      else {
+        local *F;
+        if (open F, ">$newfile") {
+          info("Writing copy of '$filename' with changes to '$newfile'");
+          print F $c;
+          close F;
+        }
+        else {
+          error("Cannot open '$newfile' for writing: $!");
+        }
+      }
+    }
+    elsif (exists $opt{patch} || $opt{changes}) {
+      if (exists $opt{patch}) {
+        unless ($patch_opened) {
+          if (open PATCH, ">$opt{patch}") {
+            $patch_opened = 1;
+          }
+          else {
+            error("Cannot open '$opt{patch}' for writing: $!");
+            delete $opt{patch};
+            $opt{changes} = 1;
+            goto fallback;
+          }
+        }
+        mydiff(\*PATCH, $filename, $c);
+      }
+      else {
+fallback:
+        info("Suggested changes:");
+        mydiff(\*STDOUT, $filename, $c);
+      }
+    }
+    else {
+      my $s = $file{changes} == 1 ? '' : 's';
+      info("$file{changes} potentially required change$s detected");
+    }
+  }
+  else {
+    info("Looks good");
+  }
+}
+
+close PATCH if $patch_opened;
+
+exit 0;
+
+
+sub mydiff
+{
+  local *F = shift;
+  my($file, $str) = @_;
+  my $diff;
+
+  if (exists $opt{diff}) {
+    $diff = run_diff($opt{diff}, $file, $str);
+  }
+
+  if (!defined $diff and can_use('Text::Diff')) {
+    $diff = Text::Diff::diff($file, \$str, { STYLE => 'Unified' });
+    $diff = <<HEADER . $diff;
+--- $file
++++ $file.patched
+HEADER
+  }
+
+  if (!defined $diff) {
+    $diff = run_diff('diff -u', $file, $str);
+  }
+
+  if (!defined $diff) {
+    $diff = run_diff('diff', $file, $str);
+  }
+
+  if (!defined $diff) {
+    error("Cannot generate a diff. Please install Text::Diff or use --copy.");
+    return;
+  }
+
+  print F $diff;
+
+}
+
+sub run_diff
+{
+  my($prog, $file, $str) = @_;
+  my $tmp = 'dppptemp';
+  my $suf = 'aaa';
+  my $diff = '';
+  local *F;
+
+  while (-e "$tmp.$suf") { $suf++ }
+  $tmp = "$tmp.$suf";
+
+  if (open F, ">$tmp") {
+    print F $str;
+    close F;
+
+    if (open F, "$prog $file $tmp |") {
+      while (<F>) {
+        s/\Q$tmp\E/$file.patched/;
+        $diff .= $_;
+      }
+      close F;
+      unlink $tmp;
+      return $diff;
+    }
+
+    unlink $tmp;
+  }
+  else {
+    error("Cannot open '$tmp' for writing: $!");
+  }
+
+  return undef;
+}
+
+sub can_use
+{
+  eval "use @_;";
+  return $@ eq '';
+}
+
+sub rec_depend
+{
+  my $func = shift;
+  my %seen;
+  return () unless exists $depends{$func};
+  grep !$seen{$_}++, map { ($_, rec_depend($_)) } @{$depends{$func}};
+}
+
+sub parse_version
+{
+  my $ver = shift;
+
+  if ($ver =~ /^(\d+)\.(\d+)\.(\d+)$/) {
+    return ($1, $2, $3);
+  }
+  elsif ($ver !~ /^\d+\.[\d_]+$/) {
+    die "cannot parse version '$ver'\n";
+  }
+
+  $ver =~ s/_//g;
+  $ver =~ s/$/000000/;
+
+  my($r,$v,$s) = $ver =~ /(\d+)\.(\d{3})(\d{3})/;
+
+  $v = int $v;
+  $s = int $s;
+
+  if ($r < 5 || ($r == 5 && $v < 6)) {
+    if ($s % 10) {
+      die "cannot parse version '$ver'\n";
+    }
+  }
+
+  return ($r, $v, $s);
+}
+
+sub format_version
+{
+  my $ver = shift;
+
+  $ver =~ s/$/000000/;
+  my($r,$v,$s) = $ver =~ /(\d+)\.(\d{3})(\d{3})/;
+
+  $v = int $v;
+  $s = int $s;
+
+  if ($r < 5 || ($r == 5 && $v < 6)) {
+    if ($s % 10) {
+      die "invalid version '$ver'\n";
+    }
+    $s /= 10;
+
+    $ver = sprintf "%d.%03d", $r, $v;
+    $s > 0 and $ver .= sprintf "_%02d", $s;
+
+    return $ver;
+  }
+
+  return sprintf "%d.%d.%d", $r, $v, $s;
+}
+
+sub info
+{
+  $opt{quiet} and return;
+  print @_, "\n";
+}
+
+sub diag
+{
+  $opt{quiet} and return;
+  $opt{diag} and print @_, "\n";
+}
+
+sub warning
+{
+  $opt{quiet} and return;
+  print "*** ", @_, "\n";
+}
+
+sub error
+{
+  print "*** ERROR: ", @_, "\n";
+}
+
+my %given_hints;
+sub hint
+{
+  $opt{quiet} and return;
+  $opt{hints} or return;
+  my $func = shift;
+  exists $hints{$func} or return;
+  $given_hints{$func}++ and return;
+  my $hint = $hints{$func};
+  $hint =~ s/^/   /mg;
+  print "   --- hint for $func ---\n", $hint;
+}
+
+sub usage
+{
+  my($usage) = do { local(@ARGV,$/)=($0); <> } =~ /^=head\d$HS+SYNOPSIS\s*^(.*?)\s*^=/ms;
+  my %M = ( 'I' => '*' );
+  $usage =~ s/^\s*perl\s+\S+/$^X $0/;
+  $usage =~ s/([A-Z])<([^>]+)>/$M{$1}$2$M{$1}/g;
+
+  print <<ENDUSAGE;
+
+Usage: $usage
+
+See perldoc $0 for details.
+
+ENDUSAGE
+
+  exit 2;
+}
+
+__DATA__
+*/
+
+#ifndef _P_P_PORTABILITY_H_
+#define _P_P_PORTABILITY_H_
+
+#ifndef DPPP_NAMESPACE
+#  define DPPP_NAMESPACE DPPP_
+#endif
+
+#define DPPP_CAT2(x,y) CAT2(x,y)
+#define DPPP_(name) DPPP_CAT2(DPPP_NAMESPACE, name)
+
+#ifndef PERL_REVISION
+#  if !defined(__PATCHLEVEL_H_INCLUDED__) && !(defined(PATCHLEVEL) && defined(SUBVERSION))
+#    define PERL_PATCHLEVEL_H_IMPLICIT
+#    include <patchlevel.h>
+#  endif
+#  if !(defined(PERL_VERSION) || (defined(SUBVERSION) && defined(PATCHLEVEL)))
+#    include <could_not_find_Perl_patchlevel.h>
+#  endif
+#  ifndef PERL_REVISION
+#    define PERL_REVISION       (5)
+     /* Replace: 1 */
+#    define PERL_VERSION        PATCHLEVEL
+#    define PERL_SUBVERSION     SUBVERSION
+     /* Replace PERL_PATCHLEVEL with PERL_VERSION */
+     /* Replace: 0 */
+#  endif
+#endif
+
+#define PERL_BCDVERSION ((PERL_REVISION * 0x1000000L) + (PERL_VERSION * 0x1000L) + PERL_SUBVERSION)
+
+/* It is very unlikely that anyone will try to use this with Perl 6
+   (or greater), but who knows.
+ */
+#if PERL_REVISION != 5
+#  error ppport.h only works with Perl version 5
+#endif /* PERL_REVISION != 5 */
+
+#ifdef I_LIMITS
+#  include <limits.h>
+#endif
+
+#ifndef PERL_UCHAR_MIN
+#  define PERL_UCHAR_MIN ((unsigned char)0)
+#endif
+
+#ifndef PERL_UCHAR_MAX
+#  ifdef UCHAR_MAX
+#    define PERL_UCHAR_MAX ((unsigned char)UCHAR_MAX)
+#  else
+#    ifdef MAXUCHAR
+#      define PERL_UCHAR_MAX ((unsigned char)MAXUCHAR)
+#    else
+#      define PERL_UCHAR_MAX ((unsigned char)~(unsigned)0)
+#    endif
+#  endif
+#endif
+
+#ifndef PERL_USHORT_MIN
+#  define PERL_USHORT_MIN ((unsigned short)0)
+#endif
+
+#ifndef PERL_USHORT_MAX
+#  ifdef USHORT_MAX
+#    define PERL_USHORT_MAX ((unsigned short)USHORT_MAX)
+#  else
+#    ifdef MAXUSHORT
+#      define PERL_USHORT_MAX ((unsigned short)MAXUSHORT)
+#    else
+#      ifdef USHRT_MAX
+#        define PERL_USHORT_MAX ((unsigned short)USHRT_MAX)
+#      else
+#        define PERL_USHORT_MAX ((unsigned short)~(unsigned)0)
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifndef PERL_SHORT_MAX
+#  ifdef SHORT_MAX
+#    define PERL_SHORT_MAX ((short)SHORT_MAX)
+#  else
+#    ifdef MAXSHORT    /* Often used in <values.h> */
+#      define PERL_SHORT_MAX ((short)MAXSHORT)
+#    else
+#      ifdef SHRT_MAX
+#        define PERL_SHORT_MAX ((short)SHRT_MAX)
+#      else
+#        define PERL_SHORT_MAX ((short) (PERL_USHORT_MAX >> 1))
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifndef PERL_SHORT_MIN
+#  ifdef SHORT_MIN
+#    define PERL_SHORT_MIN ((short)SHORT_MIN)
+#  else
+#    ifdef MINSHORT
+#      define PERL_SHORT_MIN ((short)MINSHORT)
+#    else
+#      ifdef SHRT_MIN
+#        define PERL_SHORT_MIN ((short)SHRT_MIN)
+#      else
+#        define PERL_SHORT_MIN (-PERL_SHORT_MAX - ((3 & -1) == 3))
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifndef PERL_UINT_MAX
+#  ifdef UINT_MAX
+#    define PERL_UINT_MAX ((unsigned int)UINT_MAX)
+#  else
+#    ifdef MAXUINT
+#      define PERL_UINT_MAX ((unsigned int)MAXUINT)
+#    else
+#      define PERL_UINT_MAX (~(unsigned int)0)
+#    endif
+#  endif
+#endif
+
+#ifndef PERL_UINT_MIN
+#  define PERL_UINT_MIN ((unsigned int)0)
+#endif
+
+#ifndef PERL_INT_MAX
+#  ifdef INT_MAX
+#    define PERL_INT_MAX ((int)INT_MAX)
+#  else
+#    ifdef MAXINT    /* Often used in <values.h> */
+#      define PERL_INT_MAX ((int)MAXINT)
+#    else
+#      define PERL_INT_MAX ((int)(PERL_UINT_MAX >> 1))
+#    endif
+#  endif
+#endif
+
+#ifndef PERL_INT_MIN
+#  ifdef INT_MIN
+#    define PERL_INT_MIN ((int)INT_MIN)
+#  else
+#    ifdef MININT
+#      define PERL_INT_MIN ((int)MININT)
+#    else
+#      define PERL_INT_MIN (-PERL_INT_MAX - ((3 & -1) == 3))
+#    endif
+#  endif
+#endif
+
+#ifndef PERL_ULONG_MAX
+#  ifdef ULONG_MAX
+#    define PERL_ULONG_MAX ((unsigned long)ULONG_MAX)
+#  else
+#    ifdef MAXULONG
+#      define PERL_ULONG_MAX ((unsigned long)MAXULONG)
+#    else
+#      define PERL_ULONG_MAX (~(unsigned long)0)
+#    endif
+#  endif
+#endif
+
+#ifndef PERL_ULONG_MIN
+#  define PERL_ULONG_MIN ((unsigned long)0L)
+#endif
+
+#ifndef PERL_LONG_MAX
+#  ifdef LONG_MAX
+#    define PERL_LONG_MAX ((long)LONG_MAX)
+#  else
+#    ifdef MAXLONG
+#      define PERL_LONG_MAX ((long)MAXLONG)
+#    else
+#      define PERL_LONG_MAX ((long) (PERL_ULONG_MAX >> 1))
+#    endif
+#  endif
+#endif
+
+#ifndef PERL_LONG_MIN
+#  ifdef LONG_MIN
+#    define PERL_LONG_MIN ((long)LONG_MIN)
+#  else
+#    ifdef MINLONG
+#      define PERL_LONG_MIN ((long)MINLONG)
+#    else
+#      define PERL_LONG_MIN (-PERL_LONG_MAX - ((3 & -1) == 3))
+#    endif
+#  endif
+#endif
+
+#if defined(HAS_QUAD) && (defined(convex) || defined(uts))
+#  ifndef PERL_UQUAD_MAX
+#    ifdef ULONGLONG_MAX
+#      define PERL_UQUAD_MAX ((unsigned long long)ULONGLONG_MAX)
+#    else
+#      ifdef MAXULONGLONG
+#        define PERL_UQUAD_MAX ((unsigned long long)MAXULONGLONG)
+#      else
+#        define PERL_UQUAD_MAX (~(unsigned long long)0)
+#      endif
+#    endif
+#  endif
+
+#  ifndef PERL_UQUAD_MIN
+#    define PERL_UQUAD_MIN ((unsigned long long)0L)
+#  endif
+
+#  ifndef PERL_QUAD_MAX
+#    ifdef LONGLONG_MAX
+#      define PERL_QUAD_MAX ((long long)LONGLONG_MAX)
+#    else
+#      ifdef MAXLONGLONG
+#        define PERL_QUAD_MAX ((long long)MAXLONGLONG)
+#      else
+#        define PERL_QUAD_MAX ((long long) (PERL_UQUAD_MAX >> 1))
+#      endif
+#    endif
+#  endif
+
+#  ifndef PERL_QUAD_MIN
+#    ifdef LONGLONG_MIN
+#      define PERL_QUAD_MIN ((long long)LONGLONG_MIN)
+#    else
+#      ifdef MINLONGLONG
+#        define PERL_QUAD_MIN ((long long)MINLONGLONG)
+#      else
+#        define PERL_QUAD_MIN (-PERL_QUAD_MAX - ((3 & -1) == 3))
+#      endif
+#    endif
+#  endif
+#endif
+
+/* This is based on code from 5.003 perl.h */
+#ifdef HAS_QUAD
+#  ifdef cray
+#ifndef IVTYPE
+#  define IVTYPE                         int
+#endif
+
+#ifndef IV_MIN
+#  define IV_MIN                         PERL_INT_MIN
+#endif
+
+#ifndef IV_MAX
+#  define IV_MAX                         PERL_INT_MAX
+#endif
+
+#ifndef UV_MIN
+#  define UV_MIN                         PERL_UINT_MIN
+#endif
+
+#ifndef UV_MAX
+#  define UV_MAX                         PERL_UINT_MAX
+#endif
+
+#    ifdef INTSIZE
+#ifndef IVSIZE
+#  define IVSIZE                         INTSIZE
+#endif
+
+#    endif
+#  else
+#    if defined(convex) || defined(uts)
+#ifndef IVTYPE
+#  define IVTYPE                         long long
+#endif
+
+#ifndef IV_MIN
+#  define IV_MIN                         PERL_QUAD_MIN
+#endif
+
+#ifndef IV_MAX
+#  define IV_MAX                         PERL_QUAD_MAX
+#endif
+
+#ifndef UV_MIN
+#  define UV_MIN                         PERL_UQUAD_MIN
+#endif
+
+#ifndef UV_MAX
+#  define UV_MAX                         PERL_UQUAD_MAX
+#endif
+
+#      ifdef LONGLONGSIZE
+#ifndef IVSIZE
+#  define IVSIZE                         LONGLONGSIZE
+#endif
+
+#      endif
+#    else
+#ifndef IVTYPE
+#  define IVTYPE                         long
+#endif
+
+#ifndef IV_MIN
+#  define IV_MIN                         PERL_LONG_MIN
+#endif
+
+#ifndef IV_MAX
+#  define IV_MAX                         PERL_LONG_MAX
+#endif
+
+#ifndef UV_MIN
+#  define UV_MIN                         PERL_ULONG_MIN
+#endif
+
+#ifndef UV_MAX
+#  define UV_MAX                         PERL_ULONG_MAX
+#endif
+
+#      ifdef LONGSIZE
+#ifndef IVSIZE
+#  define IVSIZE                         LONGSIZE
+#endif
+
+#      endif
+#    endif
+#  endif
+#ifndef IVSIZE
+#  define IVSIZE                         8
+#endif
+
+#ifndef PERL_QUAD_MIN
+#  define PERL_QUAD_MIN                  IV_MIN
+#endif
+
+#ifndef PERL_QUAD_MAX
+#  define PERL_QUAD_MAX                  IV_MAX
+#endif
+
+#ifndef PERL_UQUAD_MIN
+#  define PERL_UQUAD_MIN                 UV_MIN
+#endif
+
+#ifndef PERL_UQUAD_MAX
+#  define PERL_UQUAD_MAX                 UV_MAX
+#endif
+
+#else
+#ifndef IVTYPE
+#  define IVTYPE                         long
+#endif
+
+#ifndef IV_MIN
+#  define IV_MIN                         PERL_LONG_MIN
+#endif
+
+#ifndef IV_MAX
+#  define IV_MAX                         PERL_LONG_MAX
+#endif
+
+#ifndef UV_MIN
+#  define UV_MIN                         PERL_ULONG_MIN
+#endif
+
+#ifndef UV_MAX
+#  define UV_MAX                         PERL_ULONG_MAX
+#endif
+
+#endif
+
+#ifndef IVSIZE
+#  ifdef LONGSIZE
+#    define IVSIZE LONGSIZE
+#  else
+#    define IVSIZE 4 /* A bold guess, but the best we can make. */
+#  endif
+#endif
+#ifndef UVTYPE
+#  define UVTYPE                         unsigned IVTYPE
+#endif
+
+#ifndef UVSIZE
+#  define UVSIZE                         IVSIZE
+#endif
+
+#ifndef sv_setuv
+#  define sv_setuv(sv, uv)                  \
+   STMT_START {                             \
+       UV TeMpUv = uv;                      \
+       if (TeMpUv <= IV_MAX)                \
+           sv_setiv(sv, TeMpUv);            \
+       else                                 \
+           sv_setnv(sv, (double)TeMpUv);    \
+   } STMT_END
+#endif
+
+#ifndef newSVuv
+#  define newSVuv(uv) ((uv) <= IV_MAX ? newSViv((IV)uv) : newSVnv((NV)uv))
+#endif
+#ifndef sv_2uv
+#  define sv_2uv(sv)                     ((PL_Sv = (sv)), (UV) (SvNOK(PL_Sv) ? SvNV(PL_Sv) : sv_2nv(PL_Sv)))
+#endif
+
+#ifndef SvUVX
+#  define SvUVX(sv)                      ((UV)SvIVX(sv))
+#endif
+
+#ifndef SvUVXx
+#  define SvUVXx(sv)                     SvUVX(sv)
+#endif
+
+#ifndef SvUV
+#  define SvUV(sv)                       (SvIOK(sv) ? SvUVX(sv) : sv_2uv(sv))
+#endif
+
+#ifndef SvUVx
+#  define SvUVx(sv)                      ((PL_Sv = (sv)), SvUV(PL_Sv))
+#endif
+
+/* Hint: sv_uv
+ * Always use the SvUVx() macro instead of sv_uv().
+ */
+#ifndef sv_uv
+#  define sv_uv(sv)                      SvUVx(sv)
+#endif
+#ifndef XST_mUV
+#  define XST_mUV(i,v)                   (ST(i) = sv_2mortal(newSVuv(v))  )
+#endif
+
+#ifndef XSRETURN_UV
+#  define XSRETURN_UV(v)                 STMT_START { XST_mUV(0,v);  XSRETURN(1); } STMT_END
+#endif
+#ifndef PUSHu
+#  define PUSHu(u)                       STMT_START { sv_setuv(TARG, (UV)(u)); PUSHTARG;  } STMT_END
+#endif
+
+#ifndef XPUSHu
+#  define XPUSHu(u)                      STMT_START { sv_setuv(TARG, (UV)(u)); XPUSHTARG; } STMT_END
+#endif
+
+#if (PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 5))
+/* Replace: 1 */
+#  define PL_DBsingle               DBsingle
+#  define PL_DBsub                  DBsub
+#  define PL_Sv                     Sv
+#  define PL_compiling              compiling
+#  define PL_copline                copline
+#  define PL_curcop                 curcop
+#  define PL_curstash               curstash
+#  define PL_debstash               debstash
+#  define PL_defgv                  defgv
+#  define PL_diehook                diehook
+#  define PL_dirty                  dirty
+#  define PL_dowarn                 dowarn
+#  define PL_errgv                  errgv
+#  define PL_hexdigit               hexdigit
+#  define PL_hints                  hints
+#  define PL_na                            na
+#  define PL_no_modify              no_modify
+#  define PL_perl_destruct_level    perl_destruct_level
+#  define PL_perldb                 perldb
+#  define PL_ppaddr                 ppaddr
+#  define PL_rsfp_filters           rsfp_filters
+#  define PL_rsfp                   rsfp
+#  define PL_stack_base             stack_base
+#  define PL_stack_sp               stack_sp
+#  define PL_stdingv                stdingv
+#  define PL_sv_arenaroot           sv_arenaroot
+#  define PL_sv_no                  sv_no
+#  define PL_sv_undef               sv_undef
+#  define PL_sv_yes                 sv_yes
+#  define PL_tainted                tainted
+#  define PL_tainting               tainting
+/* Replace: 0 */
+#endif
+
+#ifndef PERL_UNUSED_DECL
+#  ifdef HASATTRIBUTE
+#    if (defined(__GNUC__) && defined(__cplusplus)) || defined(__INTEL_COMPILER)
+#      define PERL_UNUSED_DECL
+#    else
+#      define PERL_UNUSED_DECL __attribute__((unused))
+#    endif
+#  else
+#    define PERL_UNUSED_DECL
+#  endif
+#endif
+#ifndef NOOP
+#  define NOOP                           (void)0
+#endif
+
+#ifndef dNOOP
+#  define dNOOP                          extern int Perl___notused PERL_UNUSED_DECL
+#endif
+
+#ifndef NVTYPE
+#  if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE)
+#    define NVTYPE long double
+#  else
+#    define NVTYPE double
+#  endif
+typedef NVTYPE NV;
+#endif
+
+#ifndef INT2PTR
+
+#  if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE)
+#    define PTRV                  UV
+#    define INT2PTR(any,d)        (any)(d)
+#  else
+#    if PTRSIZE == LONGSIZE
+#      define PTRV                unsigned long
+#    else
+#      define PTRV                unsigned
+#    endif
+#    define INT2PTR(any,d)        (any)(PTRV)(d)
+#  endif
+
+#  define NUM2PTR(any,d)  (any)(PTRV)(d)
+#  define PTR2IV(p)       INT2PTR(IV,p)
+#  define PTR2UV(p)       INT2PTR(UV,p)
+#  define PTR2NV(p)       NUM2PTR(NV,p)
+
+#  if PTRSIZE == LONGSIZE
+#    define PTR2ul(p)     (unsigned long)(p)
+#  else
+#    define PTR2ul(p)     INT2PTR(unsigned long,p)
+#  endif
+
+#endif /* !INT2PTR */
+
+#undef START_EXTERN_C
+#undef END_EXTERN_C
+#undef EXTERN_C
+#ifdef __cplusplus
+#  define START_EXTERN_C extern "C" {
+#  define END_EXTERN_C }
+#  define EXTERN_C extern "C"
+#else
+#  define START_EXTERN_C
+#  define END_EXTERN_C
+#  define EXTERN_C extern
+#endif
+
+#ifndef PERL_GCC_BRACE_GROUPS_FORBIDDEN
+#  if defined(__STRICT_ANSI__) && defined(PERL_GCC_PEDANTIC)
+#    define PERL_GCC_BRACE_GROUPS_FORBIDDEN
+#  endif
+#endif
+
+#undef STMT_START
+#undef STMT_END
+#if defined(__GNUC__) && !defined(PERL_GCC_BRACE_GROUPS_FORBIDDEN) && !defined(__cplusplus)
+#  define STMT_START   (void)( /* gcc supports ``({ STATEMENTS; })'' */
+#  define STMT_END     )
+#else
+#  if defined(VOIDFLAGS) && (VOIDFLAGS) && (defined(sun) || defined(__sun__)) && !defined(__GNUC__)
+#    define STMT_START if (1)
+#    define STMT_END   else (void)0
+#  else
+#    define STMT_START do
+#    define STMT_END   while (0)
+#  endif
+#endif
+#ifndef boolSV
+#  define boolSV(b)                      ((b) ? &PL_sv_yes : &PL_sv_no)
+#endif
+
+/* DEFSV appears first in 5.004_56 */
+#ifndef DEFSV
+#  define DEFSV                          GvSV(PL_defgv)
+#endif
+
+#ifndef SAVE_DEFSV
+#  define SAVE_DEFSV                     SAVESPTR(GvSV(PL_defgv))
+#endif
+
+/* Older perls (<=5.003) lack AvFILLp */
+#ifndef AvFILLp
+#  define AvFILLp                        AvFILL
+#endif
+#ifndef ERRSV
+#  define ERRSV                          get_sv("@",FALSE)
+#endif
+#ifndef newSVpvn
+#  define newSVpvn(data,len)             ((data)                                              \
+                                    ? ((len) ? newSVpv((data), (len)) : newSVpv("", 0)) \
+                                    : newSV(0))
+#endif
+
+/* Hint: gv_stashpvn
+ * This function's backport doesn't support the length parameter, but
+ * rather ignores it. Portability can only be ensured if the length
+ * parameter is used for speed reasons, but the length can always be
+ * correctly computed from the string argument.
+ */
+#ifndef gv_stashpvn
+#  define gv_stashpvn(str,len,create)    gv_stashpv(str,create)
+#endif
+
+/* Replace: 1 */
+#ifndef get_cv
+#  define get_cv                         perl_get_cv
+#endif
+
+#ifndef get_sv
+#  define get_sv                         perl_get_sv
+#endif
+
+#ifndef get_av
+#  define get_av                         perl_get_av
+#endif
+
+#ifndef get_hv
+#  define get_hv                         perl_get_hv
+#endif
+
+/* Replace: 0 */
+
+#ifdef HAS_MEMCMP
+#ifndef memNE
+#  define memNE(s1,s2,l)                 (memcmp(s1,s2,l))
+#endif
+
+#ifndef memEQ
+#  define memEQ(s1,s2,l)                 (!memcmp(s1,s2,l))
+#endif
+
+#else
+#ifndef memNE
+#  define memNE(s1,s2,l)                 (bcmp(s1,s2,l))
+#endif
+
+#ifndef memEQ
+#  define memEQ(s1,s2,l)                 (!bcmp(s1,s2,l))
+#endif
+
+#endif
+#ifndef MoveD
+#  define MoveD(s,d,n,t)                 memmove((char*)(d),(char*)(s), (n) * sizeof(t))
+#endif
+
+#ifndef CopyD
+#  define CopyD(s,d,n,t)                 memcpy((char*)(d),(char*)(s), (n) * sizeof(t))
+#endif
+
+#ifdef HAS_MEMSET
+#ifndef ZeroD
+#  define ZeroD(d,n,t)                   memzero((char*)(d), (n) * sizeof(t))
+#endif
+
+#else
+#ifndef ZeroD
+#  define ZeroD(d,n,t)                   ((void)memzero((char*)(d), (n) * sizeof(t)),d)
+#endif
+
+#endif
+#ifndef Poison
+#  define Poison(d,n,t)                  (void)memset((char*)(d), 0xAB, (n) * sizeof(t))
+#endif
+#ifndef dUNDERBAR
+#  define dUNDERBAR                      dNOOP
+#endif
+
+#ifndef UNDERBAR
+#  define UNDERBAR                       DEFSV
+#endif
+#ifndef dAX
+#  define dAX                            I32 ax = MARK - PL_stack_base + 1
+#endif
+
+#ifndef dITEMS
+#  define dITEMS                         I32 items = SP - MARK
+#endif
+#ifndef dXSTARG
+#  define dXSTARG                        SV * targ = sv_newmortal()
+#endif
+#ifndef dTHR
+#  define dTHR                           dNOOP
+#endif
+#ifndef dTHX
+#  define dTHX                           dNOOP
+#endif
+
+#ifndef dTHXa
+#  define dTHXa(x)                       dNOOP
+#endif
+#ifndef pTHX
+#  define pTHX                           void
+#endif
+
+#ifndef pTHX_
+#  define pTHX_
+#endif
+
+#ifndef aTHX
+#  define aTHX
+#endif
+
+#ifndef aTHX_
+#  define aTHX_
+#endif
+#ifndef dTHXoa
+#  define dTHXoa(x)                      dTHXa(x)
+#endif
+#ifndef PUSHmortal
+#  define PUSHmortal                     PUSHs(sv_newmortal())
+#endif
+
+#ifndef mPUSHp
+#  define mPUSHp(p,l)                    sv_setpvn_mg(PUSHmortal, (p), (l))
+#endif
+
+#ifndef mPUSHn
+#  define mPUSHn(n)                      sv_setnv_mg(PUSHmortal, (NV)(n))
+#endif
+
+#ifndef mPUSHi
+#  define mPUSHi(i)                      sv_setiv_mg(PUSHmortal, (IV)(i))
+#endif
+
+#ifndef mPUSHu
+#  define mPUSHu(u)                      sv_setuv_mg(PUSHmortal, (UV)(u))
+#endif
+#ifndef XPUSHmortal
+#  define XPUSHmortal                    XPUSHs(sv_newmortal())
+#endif
+
+#ifndef mXPUSHp
+#  define mXPUSHp(p,l)                   STMT_START { EXTEND(sp,1); sv_setpvn_mg(PUSHmortal, (p), (l)); } STMT_END
+#endif
+
+#ifndef mXPUSHn
+#  define mXPUSHn(n)                     STMT_START { EXTEND(sp,1); sv_setnv_mg(PUSHmortal, (NV)(n)); } STMT_END
+#endif
+
+#ifndef mXPUSHi
+#  define mXPUSHi(i)                     STMT_START { EXTEND(sp,1); sv_setiv_mg(PUSHmortal, (IV)(i)); } STMT_END
+#endif
+
+#ifndef mXPUSHu
+#  define mXPUSHu(u)                     STMT_START { EXTEND(sp,1); sv_setuv_mg(PUSHmortal, (UV)(u)); } STMT_END
+#endif
+
+/* Replace: 1 */
+#ifndef call_sv
+#  define call_sv                        perl_call_sv
+#endif
+
+#ifndef call_pv
+#  define call_pv                        perl_call_pv
+#endif
+
+#ifndef call_argv
+#  define call_argv                      perl_call_argv
+#endif
+
+#ifndef call_method
+#  define call_method                    perl_call_method
+#endif
+#ifndef eval_sv
+#  define eval_sv                        perl_eval_sv
+#endif
+
+/* Replace: 0 */
+
+/* Replace perl_eval_pv with eval_pv */
+/* eval_pv depends on eval_sv */
+
+#ifndef eval_pv
+#if defined(NEED_eval_pv)
+static SV* DPPP_(my_eval_pv)(char *p, I32 croak_on_error);
+static
+#else
+extern SV* DPPP_(my_eval_pv)(char *p, I32 croak_on_error);
+#endif
+
+#ifdef eval_pv
+#  undef eval_pv
+#endif
+#define eval_pv(a,b) DPPP_(my_eval_pv)(aTHX_ a,b)
+#define Perl_eval_pv DPPP_(my_eval_pv)
+
+#if defined(NEED_eval_pv) || defined(NEED_eval_pv_GLOBAL)
+
+SV*
+DPPP_(my_eval_pv)(char *p, I32 croak_on_error)
+{
+    dSP;
+    SV* sv = newSVpv(p, 0);
+
+    PUSHMARK(sp);
+    eval_sv(sv, G_SCALAR);
+    SvREFCNT_dec(sv);
+
+    SPAGAIN;
+    sv = POPs;
+    PUTBACK;
+
+    if (croak_on_error && SvTRUE(GvSV(errgv)))
+       croak(SvPVx(GvSV(errgv), na));
+
+    return sv;
+}
+
+#endif
+#endif
+#ifndef newRV_inc
+#  define newRV_inc(sv)                  newRV(sv)   /* Replace */
+#endif
+
+#ifndef newRV_noinc
+#if defined(NEED_newRV_noinc)
+static SV * DPPP_(my_newRV_noinc)(SV *sv);
+static
+#else
+extern SV * DPPP_(my_newRV_noinc)(SV *sv);
+#endif
+
+#ifdef newRV_noinc
+#  undef newRV_noinc
+#endif
+#define newRV_noinc(a) DPPP_(my_newRV_noinc)(aTHX_ a)
+#define Perl_newRV_noinc DPPP_(my_newRV_noinc)
+
+#if defined(NEED_newRV_noinc) || defined(NEED_newRV_noinc_GLOBAL)
+SV *
+DPPP_(my_newRV_noinc)(SV *sv)
+{
+  SV *rv = (SV *)newRV(sv);
+  SvREFCNT_dec(sv);
+  return rv;
+}
+#endif
+#endif
+
+/* Hint: newCONSTSUB
+ * Returns a CV* as of perl-5.7.1. This return value is not supported
+ * by Devel::PPPort.
+ */
+
+/* newCONSTSUB from IO.xs is in the core starting with 5.004_63 */
+#if ((PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION < 63))) && ((PERL_VERSION != 4) || (PERL_SUBVERSION != 5))
+#if defined(NEED_newCONSTSUB)
+static void DPPP_(my_newCONSTSUB)(HV *stash, char *name, SV *sv);
+static
+#else
+extern void DPPP_(my_newCONSTSUB)(HV *stash, char *name, SV *sv);
+#endif
+
+#ifdef newCONSTSUB
+#  undef newCONSTSUB
+#endif
+#define newCONSTSUB(a,b,c) DPPP_(my_newCONSTSUB)(aTHX_ a,b,c)
+#define Perl_newCONSTSUB DPPP_(my_newCONSTSUB)
+
+#if defined(NEED_newCONSTSUB) || defined(NEED_newCONSTSUB_GLOBAL)
+
+void
+DPPP_(my_newCONSTSUB)(HV *stash, char *name, SV *sv)
+{
+       U32 oldhints = PL_hints;
+       HV *old_cop_stash = PL_curcop->cop_stash;
+       HV *old_curstash = PL_curstash;
+       line_t oldline = PL_curcop->cop_line;
+       PL_curcop->cop_line = PL_copline;
+
+       PL_hints &= ~HINT_BLOCK_SCOPE;
+       if (stash)
+               PL_curstash = PL_curcop->cop_stash = stash;
+
+       newSUB(
+
+#if   ((PERL_VERSION < 3) || ((PERL_VERSION == 3) && (PERL_SUBVERSION < 22)))
+               start_subparse(),
+#elif ((PERL_VERSION == 3) && (PERL_SUBVERSION == 22))
+               start_subparse(0),
+#else  /* 5.003_23  onwards */
+               start_subparse(FALSE, 0),
+#endif
+
+               newSVOP(OP_CONST, 0, newSVpv(name,0)),
+               newSVOP(OP_CONST, 0, &PL_sv_no),   /* SvPV(&PL_sv_no) == "" -- GMB */
+               newSTATEOP(0, Nullch, newSVOP(OP_CONST, 0, sv))
+       );
+
+       PL_hints = oldhints;
+       PL_curcop->cop_stash = old_cop_stash;
+       PL_curstash = old_curstash;
+       PL_curcop->cop_line = oldline;
+}
+#endif
+#endif
+
+/*
+ * Boilerplate macros for initializing and accessing interpreter-local
+ * data from C.  All statics in extensions should be reworked to use
+ * this, if you want to make the extension thread-safe.  See ext/re/re.xs
+ * for an example of the use of these macros.
+ *
+ * Code that uses these macros is responsible for the following:
+ * 1. #define MY_CXT_KEY to a unique string, e.g. "DynaLoader_guts"
+ * 2. Declare a typedef named my_cxt_t that is a structure that contains
+ *    all the data that needs to be interpreter-local.
+ * 3. Use the START_MY_CXT macro after the declaration of my_cxt_t.
+ * 4. Use the MY_CXT_INIT macro such that it is called exactly once
+ *    (typically put in the BOOT: section).
+ * 5. Use the members of the my_cxt_t structure everywhere as
+ *    MY_CXT.member.
+ * 6. Use the dMY_CXT macro (a declaration) in all the functions that
+ *    access MY_CXT.
+ */
+
+#if defined(MULTIPLICITY) || defined(PERL_OBJECT) || \
+    defined(PERL_CAPI)    || defined(PERL_IMPLICIT_CONTEXT)
+
+#ifndef START_MY_CXT
+
+/* This must appear in all extensions that define a my_cxt_t structure,
+ * right after the definition (i.e. at file scope).  The non-threads
+ * case below uses it to declare the data as static. */
+#define START_MY_CXT
+
+#if (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION < 68 ))
+/* Fetches the SV that keeps the per-interpreter data. */
+#define dMY_CXT_SV \
+       SV *my_cxt_sv = get_sv(MY_CXT_KEY, FALSE)
+#else /* >= perl5.004_68 */
+#define dMY_CXT_SV \
+       SV *my_cxt_sv = *hv_fetch(PL_modglobal, MY_CXT_KEY,             \
+                                 sizeof(MY_CXT_KEY)-1, TRUE)
+#endif /* < perl5.004_68 */
+
+/* This declaration should be used within all functions that use the
+ * interpreter-local data. */
+#define dMY_CXT        \
+       dMY_CXT_SV;                                                     \
+       my_cxt_t *my_cxtp = INT2PTR(my_cxt_t*,SvUV(my_cxt_sv))
+
+/* Creates and zeroes the per-interpreter data.
+ * (We allocate my_cxtp in a Perl SV so that it will be released when
+ * the interpreter goes away.) */
+#define MY_CXT_INIT \
+       dMY_CXT_SV;                                                     \
+       /* newSV() allocates one more than needed */                    \
+       my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\
+       Zero(my_cxtp, 1, my_cxt_t);                                     \
+       sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
+
+/* This macro must be used to access members of the my_cxt_t structure.
+ * e.g. MYCXT.some_data */
+#define MY_CXT         (*my_cxtp)
+
+/* Judicious use of these macros can reduce the number of times dMY_CXT
+ * is used.  Use is similar to pTHX, aTHX etc. */
+#define pMY_CXT                my_cxt_t *my_cxtp
+#define pMY_CXT_       pMY_CXT,
+#define _pMY_CXT       ,pMY_CXT
+#define aMY_CXT                my_cxtp
+#define aMY_CXT_       aMY_CXT,
+#define _aMY_CXT       ,aMY_CXT
+
+#endif /* START_MY_CXT */
+
+#ifndef MY_CXT_CLONE
+/* Clones the per-interpreter data. */
+#define MY_CXT_CLONE \
+       dMY_CXT_SV;                                                     \
+       my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\
+       Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t);\
+       sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
+#endif
+
+#else /* single interpreter */
+
+#ifndef START_MY_CXT
+
+#define START_MY_CXT   static my_cxt_t my_cxt;
+#define dMY_CXT_SV     dNOOP
+#define dMY_CXT                dNOOP
+#define MY_CXT_INIT    NOOP
+#define MY_CXT         my_cxt
+
+#define pMY_CXT                void
+#define pMY_CXT_
+#define _pMY_CXT
+#define aMY_CXT
+#define aMY_CXT_
+#define _aMY_CXT
+
+#endif /* START_MY_CXT */
+
+#ifndef MY_CXT_CLONE
+#define MY_CXT_CLONE   NOOP
+#endif
+
+#endif
+
+#ifndef IVdf
+#  if IVSIZE == LONGSIZE
+#    define    IVdf      "ld"
+#    define    UVuf      "lu"
+#    define    UVof      "lo"
+#    define    UVxf      "lx"
+#    define    UVXf      "lX"
+#  else
+#    if IVSIZE == INTSIZE
+#      define  IVdf      "d"
+#      define  UVuf      "u"
+#      define  UVof      "o"
+#      define  UVxf      "x"
+#      define  UVXf      "X"
+#    endif
+#  endif
+#endif
+
+#ifndef NVef
+#  if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) && \
+      defined(PERL_PRIfldbl) /* Not very likely, but let's try anyway. */
+#    define NVef          PERL_PRIeldbl
+#    define NVff          PERL_PRIfldbl
+#    define NVgf          PERL_PRIgldbl
+#  else
+#    define NVef          "e"
+#    define NVff          "f"
+#    define NVgf          "g"
+#  endif
+#endif
+
+#ifndef SvPV_nolen
+
+#if defined(NEED_sv_2pv_nolen)
+static char * DPPP_(my_sv_2pv_nolen)(pTHX_ register SV *sv);
+static
+#else
+extern char * DPPP_(my_sv_2pv_nolen)(pTHX_ register SV *sv);
+#endif
+
+#ifdef sv_2pv_nolen
+#  undef sv_2pv_nolen
+#endif
+#define sv_2pv_nolen(a) DPPP_(my_sv_2pv_nolen)(aTHX_ a)
+#define Perl_sv_2pv_nolen DPPP_(my_sv_2pv_nolen)
+
+#if defined(NEED_sv_2pv_nolen) || defined(NEED_sv_2pv_nolen_GLOBAL)
+
+char *
+DPPP_(my_sv_2pv_nolen)(pTHX_ register SV *sv)
+{
+  STRLEN n_a;
+  return sv_2pv(sv, &n_a);
+}
+
+#endif
+
+/* Hint: sv_2pv_nolen
+ * Use the SvPV_nolen() macro instead of sv_2pv_nolen().
+ */
+
+/* SvPV_nolen depends on sv_2pv_nolen */
+#define SvPV_nolen(sv) \
+          ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \
+           ? SvPVX(sv) : sv_2pv_nolen(sv))
+
+#endif
+
+#ifdef SvPVbyte
+
+/* Hint: SvPVbyte
+ * Does not work in perl-5.6.1, ppport.h implements a version
+ * borrowed from perl-5.7.3.
+ */
+
+#if ((PERL_VERSION < 7) || ((PERL_VERSION == 7) && (PERL_SUBVERSION < 0)))
+
+#if defined(NEED_sv_2pvbyte)
+static char * DPPP_(my_sv_2pvbyte)(pTHX_ register SV *sv, STRLEN *lp);
+static
+#else
+extern char * DPPP_(my_sv_2pvbyte)(pTHX_ register SV *sv, STRLEN *lp);
+#endif
+
+#ifdef sv_2pvbyte
+#  undef sv_2pvbyte
+#endif
+#define sv_2pvbyte(a,b) DPPP_(my_sv_2pvbyte)(aTHX_ a,b)
+#define Perl_sv_2pvbyte DPPP_(my_sv_2pvbyte)
+
+#if defined(NEED_sv_2pvbyte) || defined(NEED_sv_2pvbyte_GLOBAL)
+
+char *
+DPPP_(my_sv_2pvbyte)(pTHX_ register SV *sv, STRLEN *lp)
+{
+  sv_utf8_downgrade(sv,0);
+  return SvPV(sv,*lp);
+}
+
+#endif
+
+/* Hint: sv_2pvbyte
+ * Use the SvPVbyte() macro instead of sv_2pvbyte().
+ */
+
+#undef SvPVbyte
+
+/* SvPVbyte depends on sv_2pvbyte */
+#define SvPVbyte(sv, lp)                                                \
+        ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8)) == (SVf_POK)                \
+         ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_2pvbyte(sv, &lp))
+
+#endif
+
+#else
+
+#  define SvPVbyte          SvPV
+#  define sv_2pvbyte        sv_2pv
+
+#endif
+
+/* sv_2pvbyte_nolen depends on sv_2pv_nolen */
+#ifndef sv_2pvbyte_nolen
+#  define sv_2pvbyte_nolen               sv_2pv_nolen
+#endif
+
+/* Hint: sv_pvn
+ * Always use the SvPV() macro instead of sv_pvn().
+ */
+#ifndef sv_pvn
+#  define sv_pvn(sv, len)                SvPV(sv, len)
+#endif
+
+/* Hint: sv_pvn_force
+ * Always use the SvPV_force() macro instead of sv_pvn_force().
+ */
+#ifndef sv_pvn_force
+#  define sv_pvn_force(sv, len)          SvPV_force(sv, len)
+#endif
+
+#if ((PERL_VERSION > 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION >= 0))) && !defined(vnewSVpvf)
+#if defined(NEED_vnewSVpvf)
+static SV * DPPP_(my_vnewSVpvf)(pTHX_ const char * pat, va_list * args);
+static
+#else
+extern SV * DPPP_(my_vnewSVpvf)(pTHX_ const char * pat, va_list * args);
+#endif
+
+#ifdef vnewSVpvf
+#  undef vnewSVpvf
+#endif
+#define vnewSVpvf(a,b) DPPP_(my_vnewSVpvf)(aTHX_ a,b)
+#define Perl_vnewSVpvf DPPP_(my_vnewSVpvf)
+
+#if defined(NEED_vnewSVpvf) || defined(NEED_vnewSVpvf_GLOBAL)
+
+SV *
+DPPP_(my_vnewSVpvf)(pTHX_ const char *pat, va_list *args)
+{
+  register SV *sv = newSV(0);
+  sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));
+  return sv;
+}
+
+#endif
+#endif
+
+/* sv_vcatpvf depends on sv_vcatpvfn */
+#if ((PERL_VERSION > 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION >= 0))) && !defined(sv_vcatpvf)
+#  define sv_vcatpvf(sv, pat, args)  sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*))
+#endif
+
+/* sv_vsetpvf depends on sv_vsetpvfn */
+#if ((PERL_VERSION > 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION >= 0))) && !defined(sv_vsetpvf)
+#  define sv_vsetpvf(sv, pat, args)  sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*))
+#endif
+
+/* sv_catpvf_mg depends on sv_vcatpvfn, sv_catpvf_mg_nocontext */
+#if ((PERL_VERSION > 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION >= 0))) && !defined(sv_catpvf_mg)
+#if defined(NEED_sv_catpvf_mg)
+static void DPPP_(my_sv_catpvf_mg)(pTHX_ SV * sv, const char * pat, ...);
+static
+#else
+extern void DPPP_(my_sv_catpvf_mg)(pTHX_ SV * sv, const char * pat, ...);
+#endif
+
+#define Perl_sv_catpvf_mg DPPP_(my_sv_catpvf_mg)
+
+#if defined(NEED_sv_catpvf_mg) || defined(NEED_sv_catpvf_mg_GLOBAL)
+
+void
+DPPP_(my_sv_catpvf_mg)(pTHX_ SV *sv, const char *pat, ...)
+{
+  va_list args;
+  va_start(args, pat);
+  sv_vcatpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*));
+  SvSETMAGIC(sv);
+  va_end(args);
+}
+
+#endif
+#endif
+
+/* sv_catpvf_mg_nocontext depends on sv_vcatpvfn */
+#ifdef PERL_IMPLICIT_CONTEXT
+#if ((PERL_VERSION > 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION >= 0))) && !defined(sv_catpvf_mg_nocontext)
+#if defined(NEED_sv_catpvf_mg_nocontext)
+static void DPPP_(my_sv_catpvf_mg_nocontext)(SV * sv, const char * pat, ...);
+static
+#else
+extern void DPPP_(my_sv_catpvf_mg_nocontext)(SV * sv, const char * pat, ...);
+#endif
+
+#define sv_catpvf_mg_nocontext DPPP_(my_sv_catpvf_mg_nocontext)
+#define Perl_sv_catpvf_mg_nocontext DPPP_(my_sv_catpvf_mg_nocontext)
+
+#if defined(NEED_sv_catpvf_mg_nocontext) || defined(NEED_sv_catpvf_mg_nocontext_GLOBAL)
+
+void
+DPPP_(my_sv_catpvf_mg_nocontext)(SV *sv, const char *pat, ...)
+{
+  dTHX;
+  va_list args;
+  va_start(args, pat);
+  sv_vcatpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*));
+  SvSETMAGIC(sv);
+  va_end(args);
+}
+
+#endif
+#endif
+#endif
+
+#ifndef sv_catpvf_mg
+#  ifdef PERL_IMPLICIT_CONTEXT
+#    define sv_catpvf_mg   Perl_sv_catpvf_mg_nocontext
+#  else
+#    define sv_catpvf_mg   Perl_sv_catpvf_mg
+#  endif
+#endif
+
+/* sv_vcatpvf_mg depends on sv_vcatpvfn */
+#if ((PERL_VERSION > 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION >= 0))) && !defined(sv_vcatpvf_mg)
+#  define sv_vcatpvf_mg(sv, pat, args)                                     \
+   STMT_START {                                                            \
+     sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));  \
+     SvSETMAGIC(sv);                                                       \
+   } STMT_END
+#endif
+
+/* sv_setpvf_mg depends on sv_vsetpvfn, sv_setpvf_mg_nocontext */
+#if ((PERL_VERSION > 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION >= 0))) && !defined(sv_setpvf_mg)
+#if defined(NEED_sv_setpvf_mg)
+static void DPPP_(my_sv_setpvf_mg)(pTHX_ SV * sv, const char * pat, ...);
+static
+#else
+extern void DPPP_(my_sv_setpvf_mg)(pTHX_ SV * sv, const char * pat, ...);
+#endif
+
+#define Perl_sv_setpvf_mg DPPP_(my_sv_setpvf_mg)
+
+#if defined(NEED_sv_setpvf_mg) || defined(NEED_sv_setpvf_mg_GLOBAL)
+
+void
+DPPP_(my_sv_setpvf_mg)(pTHX_ SV *sv, const char *pat, ...)
+{
+  va_list args;
+  va_start(args, pat);
+  sv_vsetpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*));
+  SvSETMAGIC(sv);
+  va_end(args);
+}
+
+#endif
+#endif
+
+/* sv_setpvf_mg_nocontext depends on sv_vsetpvfn */
+#ifdef PERL_IMPLICIT_CONTEXT
+#if ((PERL_VERSION > 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION >= 0))) && !defined(sv_setpvf_mg_nocontext)
+#if defined(NEED_sv_setpvf_mg_nocontext)
+static void DPPP_(my_sv_setpvf_mg_nocontext)(SV * sv, const char * pat, ...);
+static
+#else
+extern void DPPP_(my_sv_setpvf_mg_nocontext)(SV * sv, const char * pat, ...);
+#endif
+
+#define sv_setpvf_mg_nocontext DPPP_(my_sv_setpvf_mg_nocontext)
+#define Perl_sv_setpvf_mg_nocontext DPPP_(my_sv_setpvf_mg_nocontext)
+
+#if defined(NEED_sv_setpvf_mg_nocontext) || defined(NEED_sv_setpvf_mg_nocontext_GLOBAL)
+
+void
+DPPP_(my_sv_setpvf_mg_nocontext)(SV *sv, const char *pat, ...)
+{
+  dTHX;
+  va_list args;
+  va_start(args, pat);
+  sv_vsetpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*));
+  SvSETMAGIC(sv);
+  va_end(args);
+}
+
+#endif
+#endif
+#endif
+
+#ifndef sv_setpvf_mg
+#  ifdef PERL_IMPLICIT_CONTEXT
+#    define sv_setpvf_mg   Perl_sv_setpvf_mg_nocontext
+#  else
+#    define sv_setpvf_mg   Perl_sv_setpvf_mg
+#  endif
+#endif
+
+/* sv_vsetpvf_mg depends on sv_vsetpvfn */
+#if ((PERL_VERSION > 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION >= 0))) && !defined(sv_vsetpvf_mg)
+#  define sv_vsetpvf_mg(sv, pat, args)                                     \
+   STMT_START {                                                            \
+     sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));  \
+     SvSETMAGIC(sv);                                                       \
+   } STMT_END
+#endif
+#ifndef SvGETMAGIC
+#  define SvGETMAGIC(x)                  STMT_START { if (SvGMAGICAL(x)) mg_get(x); } STMT_END
+#endif
+#ifndef PERL_MAGIC_sv
+#  define PERL_MAGIC_sv                  '\0'
+#endif
+
+#ifndef PERL_MAGIC_overload
+#  define PERL_MAGIC_overload            'A'
+#endif
+
+#ifndef PERL_MAGIC_overload_elem
+#  define PERL_MAGIC_overload_elem       'a'
+#endif
+
+#ifndef PERL_MAGIC_overload_table
+#  define PERL_MAGIC_overload_table      'c'
+#endif
+
+#ifndef PERL_MAGIC_bm
+#  define PERL_MAGIC_bm                  'B'
+#endif
+
+#ifndef PERL_MAGIC_regdata
+#  define PERL_MAGIC_regdata             'D'
+#endif
+
+#ifndef PERL_MAGIC_regdatum
+#  define PERL_MAGIC_regdatum            'd'
+#endif
+
+#ifndef PERL_MAGIC_env
+#  define PERL_MAGIC_env                 'E'
+#endif
+
+#ifndef PERL_MAGIC_envelem
+#  define PERL_MAGIC_envelem             'e'
+#endif
+
+#ifndef PERL_MAGIC_fm
+#  define PERL_MAGIC_fm                  'f'
+#endif
+
+#ifndef PERL_MAGIC_regex_global
+#  define PERL_MAGIC_regex_global        'g'
+#endif
+
+#ifndef PERL_MAGIC_isa
+#  define PERL_MAGIC_isa                 'I'
+#endif
+
+#ifndef PERL_MAGIC_isaelem
+#  define PERL_MAGIC_isaelem             'i'
+#endif
+
+#ifndef PERL_MAGIC_nkeys
+#  define PERL_MAGIC_nkeys               'k'
+#endif
+
+#ifndef PERL_MAGIC_dbfile
+#  define PERL_MAGIC_dbfile              'L'
+#endif
+
+#ifndef PERL_MAGIC_dbline
+#  define PERL_MAGIC_dbline              'l'
+#endif
+
+#ifndef PERL_MAGIC_mutex
+#  define PERL_MAGIC_mutex               'm'
+#endif
+
+#ifndef PERL_MAGIC_shared
+#  define PERL_MAGIC_shared              'N'
+#endif
+
+#ifndef PERL_MAGIC_shared_scalar
+#  define PERL_MAGIC_shared_scalar       'n'
+#endif
+
+#ifndef PERL_MAGIC_collxfrm
+#  define PERL_MAGIC_collxfrm            'o'
+#endif
+
+#ifndef PERL_MAGIC_tied
+#  define PERL_MAGIC_tied                'P'
+#endif
+
+#ifndef PERL_MAGIC_tiedelem
+#  define PERL_MAGIC_tiedelem            'p'
+#endif
+
+#ifndef PERL_MAGIC_tiedscalar
+#  define PERL_MAGIC_tiedscalar          'q'
+#endif
+
+#ifndef PERL_MAGIC_qr
+#  define PERL_MAGIC_qr                  'r'
+#endif
+
+#ifndef PERL_MAGIC_sig
+#  define PERL_MAGIC_sig                 'S'
+#endif
+
+#ifndef PERL_MAGIC_sigelem
+#  define PERL_MAGIC_sigelem             's'
+#endif
+
+#ifndef PERL_MAGIC_taint
+#  define PERL_MAGIC_taint               't'
+#endif
+
+#ifndef PERL_MAGIC_uvar
+#  define PERL_MAGIC_uvar                'U'
+#endif
+
+#ifndef PERL_MAGIC_uvar_elem
+#  define PERL_MAGIC_uvar_elem           'u'
+#endif
+
+#ifndef PERL_MAGIC_vstring
+#  define PERL_MAGIC_vstring             'V'
+#endif
+
+#ifndef PERL_MAGIC_vec
+#  define PERL_MAGIC_vec                 'v'
+#endif
+
+#ifndef PERL_MAGIC_utf8
+#  define PERL_MAGIC_utf8                'w'
+#endif
+
+#ifndef PERL_MAGIC_substr
+#  define PERL_MAGIC_substr              'x'
+#endif
+
+#ifndef PERL_MAGIC_defelem
+#  define PERL_MAGIC_defelem             'y'
+#endif
+
+#ifndef PERL_MAGIC_glob
+#  define PERL_MAGIC_glob                '*'
+#endif
+
+#ifndef PERL_MAGIC_arylen
+#  define PERL_MAGIC_arylen              '#'
+#endif
+
+#ifndef PERL_MAGIC_pos
+#  define PERL_MAGIC_pos                 '.'
+#endif
+
+#ifndef PERL_MAGIC_backref
+#  define PERL_MAGIC_backref             '<'
+#endif
+
+#ifndef PERL_MAGIC_ext
+#  define PERL_MAGIC_ext                 '~'
+#endif
+
+/* That's the best we can do... */
+#ifndef SvPV_force_nomg
+#  define SvPV_force_nomg                SvPV_force
+#endif
+
+#ifndef SvPV_nomg
+#  define SvPV_nomg                      SvPV
+#endif
+
+#ifndef sv_catpvn_nomg
+#  define sv_catpvn_nomg                 sv_catpvn
+#endif
+
+#ifndef sv_catsv_nomg
+#  define sv_catsv_nomg                  sv_catsv
+#endif
+
+#ifndef sv_setsv_nomg
+#  define sv_setsv_nomg                  sv_setsv
+#endif
+
+#ifndef sv_pvn_nomg
+#  define sv_pvn_nomg                    sv_pvn
+#endif
+
+#ifndef SvIV_nomg
+#  define SvIV_nomg                      SvIV
+#endif
+
+#ifndef SvUV_nomg
+#  define SvUV_nomg                      SvUV
+#endif
+
+#ifndef sv_catpv_mg
+#  define sv_catpv_mg(sv, ptr)          \
+   STMT_START {                         \
+     SV *TeMpSv = sv;                   \
+     sv_catpv(TeMpSv,ptr);              \
+     SvSETMAGIC(TeMpSv);                \
+   } STMT_END
+#endif
+
+#ifndef sv_catpvn_mg
+#  define sv_catpvn_mg(sv, ptr, len)    \
+   STMT_START {                         \
+     SV *TeMpSv = sv;                   \
+     sv_catpvn(TeMpSv,ptr,len);         \
+     SvSETMAGIC(TeMpSv);                \
+   } STMT_END
+#endif
+
+#ifndef sv_catsv_mg
+#  define sv_catsv_mg(dsv, ssv)         \
+   STMT_START {                         \
+     SV *TeMpSv = dsv;                  \
+     sv_catsv(TeMpSv,ssv);              \
+     SvSETMAGIC(TeMpSv);                \
+   } STMT_END
+#endif
+
+#ifndef sv_setiv_mg
+#  define sv_setiv_mg(sv, i)            \
+   STMT_START {                         \
+     SV *TeMpSv = sv;                   \
+     sv_setiv(TeMpSv,i);                \
+     SvSETMAGIC(TeMpSv);                \
+   } STMT_END
+#endif
+
+#ifndef sv_setnv_mg
+#  define sv_setnv_mg(sv, num)          \
+   STMT_START {                         \
+     SV *TeMpSv = sv;                   \
+     sv_setnv(TeMpSv,num);              \
+     SvSETMAGIC(TeMpSv);                \
+   } STMT_END
+#endif
+
+#ifndef sv_setpv_mg
+#  define sv_setpv_mg(sv, ptr)          \
+   STMT_START {                         \
+     SV *TeMpSv = sv;                   \
+     sv_setpv(TeMpSv,ptr);              \
+     SvSETMAGIC(TeMpSv);                \
+   } STMT_END
+#endif
+
+#ifndef sv_setpvn_mg
+#  define sv_setpvn_mg(sv, ptr, len)    \
+   STMT_START {                         \
+     SV *TeMpSv = sv;                   \
+     sv_setpvn(TeMpSv,ptr,len);         \
+     SvSETMAGIC(TeMpSv);                \
+   } STMT_END
+#endif
+
+#ifndef sv_setsv_mg
+#  define sv_setsv_mg(dsv, ssv)         \
+   STMT_START {                         \
+     SV *TeMpSv = dsv;                  \
+     sv_setsv(TeMpSv,ssv);              \
+     SvSETMAGIC(TeMpSv);                \
+   } STMT_END
+#endif
+
+#ifndef sv_setuv_mg
+#  define sv_setuv_mg(sv, i)            \
+   STMT_START {                         \
+     SV *TeMpSv = sv;                   \
+     sv_setuv(TeMpSv,i);                \
+     SvSETMAGIC(TeMpSv);                \
+   } STMT_END
+#endif
+
+#ifndef sv_usepvn_mg
+#  define sv_usepvn_mg(sv, ptr, len)    \
+   STMT_START {                         \
+     SV *TeMpSv = sv;                   \
+     sv_usepvn(TeMpSv,ptr,len);         \
+     SvSETMAGIC(TeMpSv);                \
+   } STMT_END
+#endif
+
+#ifdef USE_ITHREADS
+#ifndef CopFILE
+#  define CopFILE(c)                     ((c)->cop_file)
+#endif
+
+#ifndef CopFILEGV
+#  define CopFILEGV(c)                   (CopFILE(c) ? gv_fetchfile(CopFILE(c)) : Nullgv)
+#endif
+
+#ifndef CopFILE_set
+#  define CopFILE_set(c,pv)              ((c)->cop_file = savepv(pv))
+#endif
+
+#ifndef CopFILESV
+#  define CopFILESV(c)                   (CopFILE(c) ? GvSV(gv_fetchfile(CopFILE(c))) : Nullsv)
+#endif
+
+#ifndef CopFILEAV
+#  define CopFILEAV(c)                   (CopFILE(c) ? GvAV(gv_fetchfile(CopFILE(c))) : Nullav)
+#endif
+
+#ifndef CopSTASHPV
+#  define CopSTASHPV(c)                  ((c)->cop_stashpv)
+#endif
+
+#ifndef CopSTASHPV_set
+#  define CopSTASHPV_set(c,pv)           ((c)->cop_stashpv = ((pv) ? savepv(pv) : Nullch))
+#endif
+
+#ifndef CopSTASH
+#  define CopSTASH(c)                    (CopSTASHPV(c) ? gv_stashpv(CopSTASHPV(c),GV_ADD) : Nullhv)
+#endif
+
+#ifndef CopSTASH_set
+#  define CopSTASH_set(c,hv)             CopSTASHPV_set(c, (hv) ? HvNAME(hv) : Nullch)
+#endif
+
+#ifndef CopSTASH_eq
+#  define CopSTASH_eq(c,hv)              ((hv) && (CopSTASHPV(c) == HvNAME(hv) \
+                                       || (CopSTASHPV(c) && HvNAME(hv) \
+                                       && strEQ(CopSTASHPV(c), HvNAME(hv)))))
+#endif
+
+#else
+#ifndef CopFILEGV
+#  define CopFILEGV(c)                   ((c)->cop_filegv)
+#endif
+
+#ifndef CopFILEGV_set
+#  define CopFILEGV_set(c,gv)            ((c)->cop_filegv = (GV*)SvREFCNT_inc(gv))
+#endif
+
+#ifndef CopFILE_set
+#  define CopFILE_set(c,pv)              CopFILEGV_set((c), gv_fetchfile(pv))
+#endif
+
+#ifndef CopFILESV
+#  define CopFILESV(c)                   (CopFILEGV(c) ? GvSV(CopFILEGV(c)) : Nullsv)
+#endif
+
+#ifndef CopFILEAV
+#  define CopFILEAV(c)                   (CopFILEGV(c) ? GvAV(CopFILEGV(c)) : Nullav)
+#endif
+
+#ifndef CopFILE
+#  define CopFILE(c)                     (CopFILESV(c) ? SvPVX(CopFILESV(c)) : Nullch)
+#endif
+
+#ifndef CopSTASH
+#  define CopSTASH(c)                    ((c)->cop_stash)
+#endif
+
+#ifndef CopSTASH_set
+#  define CopSTASH_set(c,hv)             ((c)->cop_stash = (hv))
+#endif
+
+#ifndef CopSTASHPV
+#  define CopSTASHPV(c)                  (CopSTASH(c) ? HvNAME(CopSTASH(c)) : Nullch)
+#endif
+
+#ifndef CopSTASHPV_set
+#  define CopSTASHPV_set(c,pv)           CopSTASH_set((c), gv_stashpv(pv,GV_ADD))
+#endif
+
+#ifndef CopSTASH_eq
+#  define CopSTASH_eq(c,hv)              (CopSTASH(c) == (hv))
+#endif
+
+#endif /* USE_ITHREADS */
+#ifndef IN_PERL_COMPILETIME
+#  define IN_PERL_COMPILETIME            (PL_curcop == &PL_compiling)
+#endif
+
+#ifndef IN_LOCALE_RUNTIME
+#  define IN_LOCALE_RUNTIME              (PL_curcop->op_private & HINT_LOCALE)
+#endif
+
+#ifndef IN_LOCALE_COMPILETIME
+#  define IN_LOCALE_COMPILETIME          (PL_hints & HINT_LOCALE)
+#endif
+
+#ifndef IN_LOCALE
+#  define IN_LOCALE                      (IN_PERL_COMPILETIME ? IN_LOCALE_COMPILETIME : IN_LOCALE_RUNTIME)
+#endif
+#ifndef IS_NUMBER_IN_UV
+#  define IS_NUMBER_IN_UV                0x01
+#endif
+
+#ifndef IS_NUMBER_GREATER_THAN_UV_MAX
+#  define IS_NUMBER_GREATER_THAN_UV_MAX  0x02
+#endif
+
+#ifndef IS_NUMBER_NOT_INT
+#  define IS_NUMBER_NOT_INT              0x04
+#endif
+
+#ifndef IS_NUMBER_NEG
+#  define IS_NUMBER_NEG                  0x08
+#endif
+
+#ifndef IS_NUMBER_INFINITY
+#  define IS_NUMBER_INFINITY             0x10
+#endif
+
+#ifndef IS_NUMBER_NAN
+#  define IS_NUMBER_NAN                  0x20
+#endif
+
+/* GROK_NUMERIC_RADIX depends on grok_numeric_radix */
+#ifndef GROK_NUMERIC_RADIX
+#  define GROK_NUMERIC_RADIX(sp, send)   grok_numeric_radix(sp, send)
+#endif
+#ifndef PERL_SCAN_GREATER_THAN_UV_MAX
+#  define PERL_SCAN_GREATER_THAN_UV_MAX  0x02
+#endif
+
+#ifndef PERL_SCAN_SILENT_ILLDIGIT
+#  define PERL_SCAN_SILENT_ILLDIGIT      0x04
+#endif
+
+#ifndef PERL_SCAN_ALLOW_UNDERSCORES
+#  define PERL_SCAN_ALLOW_UNDERSCORES    0x01
+#endif
+
+#ifndef PERL_SCAN_DISALLOW_PREFIX
+#  define PERL_SCAN_DISALLOW_PREFIX      0x02
+#endif
+
+#ifndef grok_numeric_radix
+#if defined(NEED_grok_numeric_radix)
+static bool DPPP_(my_grok_numeric_radix)(pTHX_ const char ** sp, const char * send);
+static
+#else
+extern bool DPPP_(my_grok_numeric_radix)(pTHX_ const char ** sp, const char * send);
+#endif
+
+#ifdef grok_numeric_radix
+#  undef grok_numeric_radix
+#endif
+#define grok_numeric_radix(a,b) DPPP_(my_grok_numeric_radix)(aTHX_ a,b)
+#define Perl_grok_numeric_radix DPPP_(my_grok_numeric_radix)
+
+#if defined(NEED_grok_numeric_radix) || defined(NEED_grok_numeric_radix_GLOBAL)
+bool
+DPPP_(my_grok_numeric_radix)(pTHX_ const char **sp, const char *send)
+{
+#ifdef USE_LOCALE_NUMERIC
+#ifdef PL_numeric_radix_sv
+    if (PL_numeric_radix_sv && IN_LOCALE) {
+        STRLEN len;
+        char* radix = SvPV(PL_numeric_radix_sv, len);
+        if (*sp + len <= send && memEQ(*sp, radix, len)) {
+            *sp += len;
+            return TRUE;
+        }
+    }
+#else
+    /* older perls don't have PL_numeric_radix_sv so the radix
+     * must manually be requested from locale.h
+     */
+#include <locale.h>
+    dTHR;  /* needed for older threaded perls */
+    struct lconv *lc = localeconv();
+    char *radix = lc->decimal_point;
+    if (radix && IN_LOCALE) {
+        STRLEN len = strlen(radix);
+        if (*sp + len <= send && memEQ(*sp, radix, len)) {
+            *sp += len;
+            return TRUE;
+        }
+    }
+#endif /* PERL_VERSION */
+#endif /* USE_LOCALE_NUMERIC */
+    /* always try "." if numeric radix didn't match because
+     * we may have data from different locales mixed */
+    if (*sp < send && **sp == '.') {
+        ++*sp;
+        return TRUE;
+    }
+    return FALSE;
+}
+#endif
+#endif
+
+/* grok_number depends on grok_numeric_radix */
+
+#ifndef grok_number
+#if defined(NEED_grok_number)
+static int DPPP_(my_grok_number)(pTHX_ const char * pv, STRLEN len, UV * valuep);
+static
+#else
+extern int DPPP_(my_grok_number)(pTHX_ const char * pv, STRLEN len, UV * valuep);
+#endif
+
+#ifdef grok_number
+#  undef grok_number
+#endif
+#define grok_number(a,b,c) DPPP_(my_grok_number)(aTHX_ a,b,c)
+#define Perl_grok_number DPPP_(my_grok_number)
+
+#if defined(NEED_grok_number) || defined(NEED_grok_number_GLOBAL)
+int
+DPPP_(my_grok_number)(pTHX_ const char *pv, STRLEN len, UV *valuep)
+{
+  const char *s = pv;
+  const char *send = pv + len;
+  const UV max_div_10 = UV_MAX / 10;
+  const char max_mod_10 = UV_MAX % 10;
+  int numtype = 0;
+  int sawinf = 0;
+  int sawnan = 0;
+
+  while (s < send && isSPACE(*s))
+    s++;
+  if (s == send) {
+    return 0;
+  } else if (*s == '-') {
+    s++;
+    numtype = IS_NUMBER_NEG;
+  }
+  else if (*s == '+')
+  s++;
+
+  if (s == send)
+    return 0;
+
+  /* next must be digit or the radix separator or beginning of infinity */
+  if (isDIGIT(*s)) {
+    /* UVs are at least 32 bits, so the first 9 decimal digits cannot
+       overflow.  */
+    UV value = *s - '0';
+    /* This construction seems to be more optimiser friendly.
+       (without it gcc does the isDIGIT test and the *s - '0' separately)
+       With it gcc on arm is managing 6 instructions (6 cycles) per digit.
+       In theory the optimiser could deduce how far to unroll the loop
+       before checking for overflow.  */
+    if (++s < send) {
+      int digit = *s - '0';
+      if (digit >= 0 && digit <= 9) {
+        value = value * 10 + digit;
+        if (++s < send) {
+          digit = *s - '0';
+          if (digit >= 0 && digit <= 9) {
+            value = value * 10 + digit;
+            if (++s < send) {
+              digit = *s - '0';
+              if (digit >= 0 && digit <= 9) {
+                value = value * 10 + digit;
+               if (++s < send) {
+                  digit = *s - '0';
+                  if (digit >= 0 && digit <= 9) {
+                    value = value * 10 + digit;
+                    if (++s < send) {
+                      digit = *s - '0';
+                      if (digit >= 0 && digit <= 9) {
+                        value = value * 10 + digit;
+                        if (++s < send) {
+                          digit = *s - '0';
+                          if (digit >= 0 && digit <= 9) {
+                            value = value * 10 + digit;
+                            if (++s < send) {
+                              digit = *s - '0';
+                              if (digit >= 0 && digit <= 9) {
+                                value = value * 10 + digit;
+                                if (++s < send) {
+                                  digit = *s - '0';
+                                  if (digit >= 0 && digit <= 9) {
+                                    value = value * 10 + digit;
+                                    if (++s < send) {
+                                      /* Now got 9 digits, so need to check
+                                         each time for overflow.  */
+                                      digit = *s - '0';
+                                      while (digit >= 0 && digit <= 9
+                                             && (value < max_div_10
+                                                 || (value == max_div_10
+                                                     && digit <= max_mod_10))) {
+                                        value = value * 10 + digit;
+                                        if (++s < send)
+                                          digit = *s - '0';
+                                        else
+                                          break;
+                                      }
+                                      if (digit >= 0 && digit <= 9
+                                          && (s < send)) {
+                                        /* value overflowed.
+                                           skip the remaining digits, don't
+                                           worry about setting *valuep.  */
+                                        do {
+                                          s++;
+                                        } while (s < send && isDIGIT(*s));
+                                        numtype |=
+                                          IS_NUMBER_GREATER_THAN_UV_MAX;
+                                        goto skip_value;
+                                      }
+                                    }
+                                  }
+                               }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+       }
+      }
+    }
+    numtype |= IS_NUMBER_IN_UV;
+    if (valuep)
+      *valuep = value;
+
+  skip_value:
+    if (GROK_NUMERIC_RADIX(&s, send)) {
+      numtype |= IS_NUMBER_NOT_INT;
+      while (s < send && isDIGIT(*s))  /* optional digits after the radix */
+        s++;
+    }
+  }
+  else if (GROK_NUMERIC_RADIX(&s, send)) {
+    numtype |= IS_NUMBER_NOT_INT | IS_NUMBER_IN_UV; /* valuep assigned below */
+    /* no digits before the radix means we need digits after it */
+    if (s < send && isDIGIT(*s)) {
+      do {
+        s++;
+      } while (s < send && isDIGIT(*s));
+      if (valuep) {
+        /* integer approximation is valid - it's 0.  */
+        *valuep = 0;
+      }
+    }
+    else
+      return 0;
+  } else if (*s == 'I' || *s == 'i') {
+    s++; if (s == send || (*s != 'N' && *s != 'n')) return 0;
+    s++; if (s == send || (*s != 'F' && *s != 'f')) return 0;
+    s++; if (s < send && (*s == 'I' || *s == 'i')) {
+      s++; if (s == send || (*s != 'N' && *s != 'n')) return 0;
+      s++; if (s == send || (*s != 'I' && *s != 'i')) return 0;
+      s++; if (s == send || (*s != 'T' && *s != 't')) return 0;
+      s++; if (s == send || (*s != 'Y' && *s != 'y')) return 0;
+      s++;
+    }
+    sawinf = 1;
+  } else if (*s == 'N' || *s == 'n') {
+    /* XXX TODO: There are signaling NaNs and quiet NaNs. */
+    s++; if (s == send || (*s != 'A' && *s != 'a')) return 0;
+    s++; if (s == send || (*s != 'N' && *s != 'n')) return 0;
+    s++;
+    sawnan = 1;
+  } else
+    return 0;
+
+  if (sawinf) {
+    numtype &= IS_NUMBER_NEG; /* Keep track of sign  */
+    numtype |= IS_NUMBER_INFINITY | IS_NUMBER_NOT_INT;
+  } else if (sawnan) {
+    numtype &= IS_NUMBER_NEG; /* Keep track of sign  */
+    numtype |= IS_NUMBER_NAN | IS_NUMBER_NOT_INT;
+  } else if (s < send) {
+    /* we can have an optional exponent part */
+    if (*s == 'e' || *s == 'E') {
+      /* The only flag we keep is sign.  Blow away any "it's UV"  */
+      numtype &= IS_NUMBER_NEG;
+      numtype |= IS_NUMBER_NOT_INT;
+      s++;
+      if (s < send && (*s == '-' || *s == '+'))
+        s++;
+      if (s < send && isDIGIT(*s)) {
+        do {
+          s++;
+        } while (s < send && isDIGIT(*s));
+      }
+      else
+      return 0;
+    }
+  }
+  while (s < send && isSPACE(*s))
+    s++;
+  if (s >= send)
+    return numtype;
+  if (len == 10 && memEQ(pv, "0 but true", 10)) {
+    if (valuep)
+      *valuep = 0;
+    return IS_NUMBER_IN_UV;
+  }
+  return 0;
+}
+#endif
+#endif
+
+/*
+ * The grok_* routines have been modified to use warn() instead of
+ * Perl_warner(). Also, 'hexdigit' was the former name of PL_hexdigit,
+ * which is why the stack variable has been renamed to 'xdigit'.
+ */
+
+#ifndef grok_bin
+#if defined(NEED_grok_bin)
+static UV DPPP_(my_grok_bin)(pTHX_ char *start, STRLEN *len_p, I32 *flags, NV *result);
+static
+#else
+extern UV DPPP_(my_grok_bin)(pTHX_ char *start, STRLEN *len_p, I32 *flags, NV *result);
+#endif
+
+#ifdef grok_bin
+#  undef grok_bin
+#endif
+#define grok_bin(a,b,c,d) DPPP_(my_grok_bin)(aTHX_ a,b,c,d)
+#define Perl_grok_bin DPPP_(my_grok_bin)
+
+#if defined(NEED_grok_bin) || defined(NEED_grok_bin_GLOBAL)
+UV
+DPPP_(my_grok_bin)(pTHX_ char *start, STRLEN *len_p, I32 *flags, NV *result)
+{
+    const char *s = start;
+    STRLEN len = *len_p;
+    UV value = 0;
+    NV value_nv = 0;
+
+    const UV max_div_2 = UV_MAX / 2;
+    bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES;
+    bool overflowed = FALSE;
+
+    if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) {
+        /* strip off leading b or 0b.
+           for compatibility silently suffer "b" and "0b" as valid binary
+           numbers. */
+        if (len >= 1) {
+            if (s[0] == 'b') {
+                s++;
+                len--;
+            }
+            else if (len >= 2 && s[0] == '0' && s[1] == 'b') {
+                s+=2;
+                len-=2;
+            }
+        }
+    }
+
+    for (; len-- && *s; s++) {
+        char bit = *s;
+        if (bit == '0' || bit == '1') {
+            /* Write it in this wonky order with a goto to attempt to get the
+               compiler to make the common case integer-only loop pretty tight.
+               With gcc seems to be much straighter code than old scan_bin.  */
+          redo:
+            if (!overflowed) {
+                if (value <= max_div_2) {
+                    value = (value << 1) | (bit - '0');
+                    continue;
+                }
+                /* Bah. We're just overflowed.  */
+                warn("Integer overflow in binary number");
+                overflowed = TRUE;
+                value_nv = (NV) value;
+            }
+            value_nv *= 2.0;
+           /* If an NV has not enough bits in its mantissa to
+            * represent a UV this summing of small low-order numbers
+            * is a waste of time (because the NV cannot preserve
+            * the low-order bits anyway): we could just remember when
+            * did we overflow and in the end just multiply value_nv by the
+            * right amount. */
+            value_nv += (NV)(bit - '0');
+            continue;
+        }
+        if (bit == '_' && len && allow_underscores && (bit = s[1])
+            && (bit == '0' || bit == '1'))
+           {
+               --len;
+               ++s;
+                goto redo;
+           }
+        if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT))
+            warn("Illegal binary digit '%c' ignored", *s);
+        break;
+    }
+
+    if (   ( overflowed && value_nv > 4294967295.0)
+#if UVSIZE > 4
+       || (!overflowed && value > 0xffffffff  )
+#endif
+       ) {
+       warn("Binary number > 0b11111111111111111111111111111111 non-portable");
+    }
+    *len_p = s - start;
+    if (!overflowed) {
+        *flags = 0;
+        return value;
+    }
+    *flags = PERL_SCAN_GREATER_THAN_UV_MAX;
+    if (result)
+        *result = value_nv;
+    return UV_MAX;
+}
+#endif
+#endif
+
+#ifndef grok_hex
+#if defined(NEED_grok_hex)
+static UV DPPP_(my_grok_hex)(pTHX_ char *start, STRLEN *len_p, I32 *flags, NV *result);
+static
+#else
+extern UV DPPP_(my_grok_hex)(pTHX_ char *start, STRLEN *len_p, I32 *flags, NV *result);
+#endif
+
+#ifdef grok_hex
+#  undef grok_hex
+#endif
+#define grok_hex(a,b,c,d) DPPP_(my_grok_hex)(aTHX_ a,b,c,d)
+#define Perl_grok_hex DPPP_(my_grok_hex)
+
+#if defined(NEED_grok_hex) || defined(NEED_grok_hex_GLOBAL)
+UV
+DPPP_(my_grok_hex)(pTHX_ char *start, STRLEN *len_p, I32 *flags, NV *result)
+{
+    const char *s = start;
+    STRLEN len = *len_p;
+    UV value = 0;
+    NV value_nv = 0;
+
+    const UV max_div_16 = UV_MAX / 16;
+    bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES;
+    bool overflowed = FALSE;
+    const char *xdigit;
+
+    if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) {
+        /* strip off leading x or 0x.
+           for compatibility silently suffer "x" and "0x" as valid hex numbers.
+        */
+        if (len >= 1) {
+            if (s[0] == 'x') {
+                s++;
+                len--;
+            }
+            else if (len >= 2 && s[0] == '0' && s[1] == 'x') {
+                s+=2;
+                len-=2;
+            }
+        }
+    }
+
+    for (; len-- && *s; s++) {
+       xdigit = strchr((char *) PL_hexdigit, *s);
+        if (xdigit) {
+            /* Write it in this wonky order with a goto to attempt to get the
+               compiler to make the common case integer-only loop pretty tight.
+               With gcc seems to be much straighter code than old scan_hex.  */
+          redo:
+            if (!overflowed) {
+                if (value <= max_div_16) {
+                    value = (value << 4) | ((xdigit - PL_hexdigit) & 15);
+                    continue;
+                }
+                warn("Integer overflow in hexadecimal number");
+                overflowed = TRUE;
+                value_nv = (NV) value;
+            }
+            value_nv *= 16.0;
+           /* If an NV has not enough bits in its mantissa to
+            * represent a UV this summing of small low-order numbers
+            * is a waste of time (because the NV cannot preserve
+            * the low-order bits anyway): we could just remember when
+            * did we overflow and in the end just multiply value_nv by the
+            * right amount of 16-tuples. */
+            value_nv += (NV)((xdigit - PL_hexdigit) & 15);
+            continue;
+        }
+        if (*s == '_' && len && allow_underscores && s[1]
+               && (xdigit = strchr((char *) PL_hexdigit, s[1])))
+           {
+               --len;
+               ++s;
+                goto redo;
+           }
+        if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT))
+            warn("Illegal hexadecimal digit '%c' ignored", *s);
+        break;
+    }
+
+    if (   ( overflowed && value_nv > 4294967295.0)
+#if UVSIZE > 4
+       || (!overflowed && value > 0xffffffff  )
+#endif
+       ) {
+       warn("Hexadecimal number > 0xffffffff non-portable");
+    }
+    *len_p = s - start;
+    if (!overflowed) {
+        *flags = 0;
+        return value;
+    }
+    *flags = PERL_SCAN_GREATER_THAN_UV_MAX;
+    if (result)
+        *result = value_nv;
+    return UV_MAX;
+}
+#endif
+#endif
+
+#ifndef grok_oct
+#if defined(NEED_grok_oct)
+static UV DPPP_(my_grok_oct)(pTHX_ char *start, STRLEN *len_p, I32 *flags, NV *result);
+static
+#else
+extern UV DPPP_(my_grok_oct)(pTHX_ char *start, STRLEN *len_p, I32 *flags, NV *result);
+#endif
+
+#ifdef grok_oct
+#  undef grok_oct
+#endif
+#define grok_oct(a,b,c,d) DPPP_(my_grok_oct)(aTHX_ a,b,c,d)
+#define Perl_grok_oct DPPP_(my_grok_oct)
+
+#if defined(NEED_grok_oct) || defined(NEED_grok_oct_GLOBAL)
+UV
+DPPP_(my_grok_oct)(pTHX_ char *start, STRLEN *len_p, I32 *flags, NV *result)
+{
+    const char *s = start;
+    STRLEN len = *len_p;
+    UV value = 0;
+    NV value_nv = 0;
+
+    const UV max_div_8 = UV_MAX / 8;
+    bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES;
+    bool overflowed = FALSE;
+
+    for (; len-- && *s; s++) {
+         /* gcc 2.95 optimiser not smart enough to figure that this subtraction
+            out front allows slicker code.  */
+        int digit = *s - '0';
+        if (digit >= 0 && digit <= 7) {
+            /* Write it in this wonky order with a goto to attempt to get the
+               compiler to make the common case integer-only loop pretty tight.
+            */
+          redo:
+            if (!overflowed) {
+                if (value <= max_div_8) {
+                    value = (value << 3) | digit;
+                    continue;
+                }
+                /* Bah. We're just overflowed.  */
+                warn("Integer overflow in octal number");
+                overflowed = TRUE;
+                value_nv = (NV) value;
+            }
+            value_nv *= 8.0;
+           /* If an NV has not enough bits in its mantissa to
+            * represent a UV this summing of small low-order numbers
+            * is a waste of time (because the NV cannot preserve
+            * the low-order bits anyway): we could just remember when
+            * did we overflow and in the end just multiply value_nv by the
+            * right amount of 8-tuples. */
+            value_nv += (NV)digit;
+            continue;
+        }
+        if (digit == ('_' - '0') && len && allow_underscores
+            && (digit = s[1] - '0') && (digit >= 0 && digit <= 7))
+           {
+               --len;
+               ++s;
+                goto redo;
+           }
+        /* Allow \octal to work the DWIM way (that is, stop scanning
+         * as soon as non-octal characters are seen, complain only iff
+         * someone seems to want to use the digits eight and nine). */
+        if (digit == 8 || digit == 9) {
+            if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT))
+                warn("Illegal octal digit '%c' ignored", *s);
+        }
+        break;
+    }
+
+    if (   ( overflowed && value_nv > 4294967295.0)
+#if UVSIZE > 4
+       || (!overflowed && value > 0xffffffff  )
+#endif
+       ) {
+       warn("Octal number > 037777777777 non-portable");
+    }
+    *len_p = s - start;
+    if (!overflowed) {
+        *flags = 0;
+        return value;
+    }
+    *flags = PERL_SCAN_GREATER_THAN_UV_MAX;
+    if (result)
+        *result = value_nv;
+    return UV_MAX;
+}
+#endif
+#endif
+
+#ifdef NO_XSLOCKS
+#  ifdef dJMPENV
+#    define dXCPT             dJMPENV; int rEtV = 0
+#    define XCPT_TRY_START    JMPENV_PUSH(rEtV); if (rEtV == 0)
+#    define XCPT_TRY_END      JMPENV_POP;
+#    define XCPT_CATCH        if (rEtV != 0)
+#    define XCPT_RETHROW      JMPENV_JUMP(rEtV)
+#  else
+#    define dXCPT             Sigjmp_buf oldTOP; int rEtV = 0
+#    define XCPT_TRY_START    Copy(top_env, oldTOP, 1, Sigjmp_buf); rEtV = Sigsetjmp(top_env, 1); if (rEtV == 0)
+#    define XCPT_TRY_END      Copy(oldTOP, top_env, 1, Sigjmp_buf);
+#    define XCPT_CATCH        if (rEtV != 0)
+#    define XCPT_RETHROW      Siglongjmp(top_env, rEtV)
+#  endif
+#endif
+
+#endif /* _P_P_PORTABILITY_H_ */
+
+/* End of File ppport.h */
diff --git a/perl-module/t/Pspp.t b/perl-module/t/Pspp.t
new file mode 100644 (file)
index 0000000..04b76a5
--- /dev/null
@@ -0,0 +1,624 @@
+# -*-perl-*-
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl PSPP.t'
+
+#########################
+
+# change 'tests => 1' to 'tests => last_test_to_print';
+
+use Test::More tests => 37;
+use Text::Diff;
+use File::Temp qw/ tempfile tempdir /;
+BEGIN { use_ok('PSPP') };
+
+#########################
+
+sub compare
+{
+    my $file = shift;
+    my $pattern = shift;
+    return ! diff ("$file", \$pattern);
+}
+
+my $pspp_cmd = $ENV{PSPP_TEST_CMD};
+
+if ( ! $pspp_cmd)
+{
+    $pspp_cmd="pspp";
+}
+
+sub run_pspp_syntax
+{
+    my $tempdir = shift;
+    my $syntax = shift;
+
+    my $syntaxfile = "$tempdir/foo.sps";
+
+    open (FH, ">$syntaxfile");
+    print FH "$syntax";
+    close (FH);
+
+    system ("cd $tempdir; $pspp_cmd -o raw-ascii $syntaxfile");
+}
+
+sub run_pspp_syntax_cmp
+{
+    my $tempdir = shift;
+    my $syntax = shift;
+
+    my $result = shift;
+
+    run_pspp_syntax ($tempdir, $syntax);
+
+    my $diff =  diff ("$tempdir/pspp.list", \$result);
+
+    if ( ! ($diff eq ""))
+    {
+       diag ("$diff");
+    }
+
+    return ($diff eq "");
+}
+
+
+# Insert your test code below, the Test::More module is used here so read
+# its man page ( perldoc Test::More ) for help writing this test script.
+
+{
+  my $d = PSPP::Dict->new();
+  ok (ref $d, "Dictionary Creation");
+  ok ($d->get_var_cnt () == 0);
+
+  $d->set_label ("My Dictionary");
+  $d->set_documents ("These Documents");
+
+  # Tests for variable creation
+
+  my $var0 = PSPP::Var->new ($d, "le");
+  ok (!ref $var0, "Trap illegal variable name");
+  ok ($d->get_var_cnt () == 0);
+
+  $var0 = PSPP::Var->new ($d, "legal");
+  ok (ref $var0, "Accept legal variable name");
+  ok ($d->get_var_cnt () == 1);
+
+  my $var1 = PSPP::Var->new ($d, "legal");
+  ok (!ref $var1, "Trap duplicate variable name");
+  ok ($d->get_var_cnt () == 1);
+
+  $var1 = PSPP::Var->new ($d, "money", 
+                         (fmt=>PSPP::Fmt::DOLLAR, 
+                          width=>4, decimals=>2) );
+  ok (ref $var1, "Accept valid format");
+  ok ($d->get_var_cnt () == 2);
+
+  $d->set_weight ($var1);
+
+
+  # Tests for system file creation
+  # Make sure a system file can be created
+  {
+      my $tempdir = tempdir( CLEANUP => 1 );
+      my $tempfile = "$tempdir/testfile.sav";
+      my $syntaxfile = "$tempdir/syntax.sps";
+      my $sysfile = PSPP::Sysfile->new ("$tempfile", $d);
+      ok (ref $sysfile, "Create sysfile object");
+
+      $sysfile->close ();
+      ok (-s "$tempfile", "Write system file");
+  }
+}
+
+
+# Make sure we can write cases to a file
+{
+  my $d = PSPP::Dict->new();
+  PSPP::Var->new ($d, "id",
+                        (
+                         fmt=>PSPP::Fmt::F, 
+                         width=>2, 
+                         decimals=>0
+                         )
+                        );
+
+  PSPP::Var->new ($d, "name",
+                        (
+                         fmt=>PSPP::Fmt::A, 
+                         width=>20, 
+                         )
+                        );
+
+  $d->set_documents ("This should not appear");
+  $d->clear_documents ();
+  $d->add_document ("This is a document line");
+
+  $d->set_label ("This is the file label");
+
+  # Check that we can write system files
+  {
+      my $tempdir = tempdir( CLEANUP => 1 );
+      my $tempfile = "$tempdir/testfile.sav";
+      my $sysfile = PSPP::Sysfile->new ("$tempfile", $d);
+
+      my $res = $sysfile->append_case ( [34, "frederick"]);
+      ok ($res, "Append Case");
+
+      $res = $sysfile->append_case ( [34, "frederick", "extra"]);
+      ok (!$res, "Appending Case with too many variables");
+
+      $sysfile->close ();
+      ok (-s  "$tempfile", "existance");
+  }
+
+  # Check that sysfiles are closed properly
+  {
+      my $tempdir = tempdir( CLEANUP => 1 );
+      my $tempfile = "$tempdir/testfile.sav";
+      {
+         my $sysfile = PSPP::Sysfile->new ("$tempfile", $d);
+
+         my $res = $sysfile->append_case ( [21, "wheelbarrow"]);
+         ok ($res, "Append Case 2");
+
+         # Don't close.  We want to test that the destructor  does that 
+         # automatically 
+      }
+      ok (-s "$tempfile", "existance2");
+
+    ok (run_pspp_syntax_cmp ($tempdir, <<SYNTAX, <<RESULT), "Check output");
+
+        GET FILE='$tempfile'.
+       DISPLAY DICTIONARY.
+       DISPLAY FILE LABEL.
+       DISPLAY DOCUMENTS.
+       LIST.
+SYNTAX
+1.1 DISPLAY.  
++--------+-------------------------------------------+--------+
+|Variable|Description                                |Position|
+#========#===========================================#========#
+|id      |Format: F2.0                               |       1|
+|        |Measure: Scale                             |        |
+|        |Display Alignment: Right                   |        |
+|        |Display Width: 8                           |        |
++--------+-------------------------------------------+--------+
+|name    |Format: A20                                |       2|
+|        |Measure: Nominal                           |        |
+|        |Display Alignment: Left                    |        |
+|        |Display Width: 20                          |        |
++--------+-------------------------------------------+--------+
+
+File label:
+This is the file label
+
+Documents in the active file:
+
+This is a document line
+
+id                 name
+-- --------------------
+21 wheelbarrow          
+
+RESULT
+
+
+  }
+
+  # Now do some tests to make sure all the variable parameters 
+  # can be written properly.
+
+  {
+      my $tempdir = tempdir( CLEANUP => 1 );
+      my $tempfile = "$tempdir/testfile.sav";      
+      my $dict = PSPP::Dict->new();
+      ok (ref $dict, "Dictionary Creation 2");
+
+      my $int = PSPP::Var->new ($dict, "integer", 
+                               (width=>8, decimals=>0) );
+
+      $int->set_label ("My Integer");
+      
+      $int->add_value_label (99, "Silly");
+      $int->clear_value_labels ();
+      $int->add_value_label (0, "Zero");
+      $int->add_value_label (1, "Unity");
+      $int->add_value_label (2, "Duality");
+
+      my $str = PSPP::Var->new ($dict, "string", 
+                               (fmt=>PSPP::Fmt::A, width=>8) );
+
+
+      $str->set_label ("My String");
+      ok ($str->add_value_label ("xx", "foo"), "Value label for short string");
+      diag ($PSPP::errstr);
+      $str->add_value_label ("yy", "bar");
+
+      $str->set_missing_values ("this", "that");
+
+      my $longstr = PSPP::Var->new ($dict, "longstring", 
+                               (fmt=>PSPP::Fmt::A, width=>9) );
+
+
+      $longstr->set_label ("My Long String");
+      my $re = $longstr->add_value_label ("xxx", "xfoo");
+      ok (($re == 0), "Long strings cant have labels");
+
+      ok ($PSPP::errstr eq "Cannot add label to a long string variable", "Error msg");
+
+      $int->set_missing_values (9, 99);
+
+      my $sysfile = PSPP::Sysfile->new ("$tempfile", $dict);
+
+
+      $sysfile->close ();
+
+      ok (run_pspp_syntax_cmp ($tempdir, <<SYNTAX, <<RESULT), "Check output 2");
+GET FILE='$tempfile'.
+DISPLAY DICTIONARY.
+SYNTAX
+1.1 DISPLAY.  
++----------+-----------------------------------------+--------+
+|Variable  |Description                              |Position|
+#==========#=========================================#========#
+|integer   |My Integer                               |       1|
+|          |Format: F8.0                             |        |
+|          |Measure: Scale                           |        |
+|          |Display Alignment: Right                 |        |
+|          |Display Width: 8                         |        |
+|          |Missing Values: 9; 99                    |        |
+|          +-----+-----------------------------------+        |
+|          |    0|Zero                               |        |
+|          |    1|Unity                              |        |
+|          |    2|Duality                            |        |
++----------+-----+-----------------------------------+--------+
+|string    |My String                                |       2|
+|          |Format: A8                               |        |
+|          |Measure: Nominal                         |        |
+|          |Display Alignment: Left                  |        |
+|          |Display Width: 8                         |        |
+|          |Missing Values: "this    "; "that    "   |        |
+|          +-----+-----------------------------------+        |
+|          |   xx|foo                                |        |
+|          |   yy|bar                                |        |
++----------+-----+-----------------------------------+--------+
+|longstring|My Long String                           |       3|
+|          |Format: A9                               |        |
+|          |Measure: Nominal                         |        |
+|          |Display Alignment: Left                  |        |
+|          |Display Width: 9                         |        |
++----------+-----------------------------------------+--------+
+
+RESULT
+
+  }
+
+}
+
+sub generate_sav_file 
+{
+    my $filename = shift;
+    my $tempdir = shift;
+
+    run_pspp_syntax_cmp ($tempdir, <<SYNTAX, <<RESULT);
+data list notable list /string (a8) longstring (a12) numeric (f10) date (date11) dollar (dollar8.2) datetime (datetime17)
+begin data.
+1111 One   1 1/1/1 1   1/1/1+01:01
+2222 Two   2 2/2/2 2   2/2/2+02:02
+3333 Three 3 3/3/3 3   3/3/3+03:03
+.    .     . .         .
+5555 Five  5 5/5/5 5   5/5/5+05:05
+end data.
+
+
+variable labels string 'A Short String Variable'
+  /longstring 'A Long String Variable'
+  /numeric 'A Numeric Variable'
+  /date 'A Date Variable'
+  /dollar 'A Dollar Variable'
+  /datetime 'A Datetime Variable'.
+
+
+missing values numeric (9, 5, 999).
+
+missing values string ("3333").
+
+add value labels
+  /string '1111' 'ones' '2222' 'twos' '3333' 'threes'
+  /numeric 1 'Unity' 2 'Duality' 3 'Thripality'.
+
+variable attribute
+    variables = numeric
+    attribute=colour[1]('blue') colour[2]('pink') colour[3]('violet')
+    attribute=size('large') nationality('foreign').
+
+
+save outfile='$filename'.
+SYNTAX
+
+RESULT
+
+}
+
+
+# Test to make sure that the dictionary survives the sysfile.
+# Thanks to Rob Messer for reporting this problem
+{
+    my $tempdir = tempdir( CLEANUP => 1 );
+    my $tempfile = "$tempdir/testfile.sav";
+    my $sysfile ;
+
+    {
+       my $d = PSPP::Dict->new();
+
+       PSPP::Var->new ($d, "id",
+                       (
+                        fmt=>PSPP::Fmt::F, 
+                        width=>2, 
+                        decimals=>0
+                        )
+                       );
+
+       $sysfile = PSPP::Sysfile->new ("$tempfile", $d);
+    }
+
+    my $res = $sysfile->append_case ([3]);
+
+    ok ($res, "Dictionary survives sysfile");
+}
+
+
+# Basic reader test
+{
+ my $tempdir = tempdir( CLEANUP => 1 );
+
+ generate_sav_file ("$tempdir/in.sav", "$tempdir");
+
+ my $sf = PSPP::Reader->open ("$tempdir/in.sav");
+
+ my $dict = $sf->get_dict ();
+
+ open (MYFILE, ">$tempdir/out.txt");
+ for ($v = 0 ; $v < $dict->get_var_cnt() ; $v++)
+ {
+    my $var = $dict->get_var ($v);
+    my $name = $var->get_name ();
+    my $label = $var->get_label ();
+
+    print MYFILE "Variable $v is \"$name\", label is \"$label\"\n";
+    
+    my $vl = $var->get_value_labels ();
+
+    print MYFILE "Value Labels:\n";
+    print MYFILE "$_ => $vl->{$_}\n" for keys %$vl;
+ }
+
+ while (my @c = $sf->get_next_case () )
+ {
+    for ($v = 0; $v < $dict->get_var_cnt(); $v++)
+    {
+       print MYFILE "val$v: \"$c[$v]\"\n";
+    }
+    print MYFILE "\n";
+ }
+
+ close (MYFILE);
+
+ok (compare ("$tempdir/out.txt", <<EOF), "Basic reader operation");
+Variable 0 is "string", label is "A Short String Variable"
+Value Labels:
+3333     => threes
+1111     => ones
+2222     => twos
+Variable 1 is "longstring", label is "A Long String Variable"
+Value Labels:
+Variable 2 is "numeric", label is "A Numeric Variable"
+Value Labels:
+1 => Unity
+3 => Thripality
+2 => Duality
+Variable 3 is "date", label is "A Date Variable"
+Value Labels:
+Variable 4 is "dollar", label is "A Dollar Variable"
+Value Labels:
+Variable 5 is "datetime", label is "A Datetime Variable"
+Value Labels:
+val0: "1111    "
+val1: "One         "
+val2: "1"
+val3: "13197686400"
+val4: "1"
+val5: "13197690060"
+
+val0: "2222    "
+val1: "Two         "
+val2: "2"
+val3: "13231987200"
+val4: "2"
+val5: "13231994520"
+
+val0: "3333    "
+val1: "Three       "
+val2: "3"
+val3: "13266028800"
+val4: "3"
+val5: "13266039780"
+
+val0: ".       "
+val1: ".           "
+val2: ""
+val3: ""
+val4: ""
+val5: ""
+
+val0: "5555    "
+val1: "Five        "
+val2: "5"
+val3: "13334630400"
+val4: "5"
+val5: "13334648700"
+
+EOF
+
+}
+
+
+# Check that we can stream one file into another
+{
+ my $tempdir = tempdir( CLEANUP => 1 );
+
+ generate_sav_file ("$tempdir/in.sav", "$tempdir");
+
+ my $input = PSPP::Reader->open ("$tempdir/in.sav");
+
+ my $dict = $input->get_dict ();
+
+ my $output = PSPP::Sysfile->new ("$tempdir/out.sav", $dict);
+
+ while (my (@c) = $input->get_next_case () )
+ {
+   $output->append_case (\@c);
+ }
+
+ $output->close ();
+
+
+ #Check the two files are the same (except for metadata)
+
+ run_pspp_syntax ($tempdir, <<SYNTAX);
+ get file='$tempdir/in.sav'.
+ display dictionary.
+ list.
+
+SYNTAX
+
+ system ("cp $tempdir/pspp.list $tempdir/in.txt");
+
+ run_pspp_syntax ($tempdir, <<SYNTAX);
+ get file='$tempdir/out.sav'.
+ display dictionary.
+ list.
+
+SYNTAX
+ ok (! diff ("$tempdir/pspp.list", "$tempdir/in.txt"), "Streaming of files");
+}
+
+
+
+# Check that the format_value function works properly
+{
+ my $tempdir = tempdir( CLEANUP => 1 );
+
+ run_pspp_syntax ($tempdir, <<SYNTAX);
+
+data list list /d (datetime17).
+begin data.
+11/9/2001+08:20
+end data.
+
+save outfile='$tempdir/dd.sav'.
+
+SYNTAX
+
+ my $sf = PSPP::Reader->open ("$tempdir/dd.sav");
+
+ my $dict = $sf->get_dict ();
+
+ my (@c) = $sf->get_next_case ();
+
+ my $var = $dict->get_var (0);
+ my $val = $c[0];
+ my $formatted = PSPP::format_value ($val, $var);
+ my $str = gmtime ($val - PSPP::PERL_EPOCH);
+ print "Formatted string is \"$formatted\"\n";
+ ok ( $formatted eq "11-SEP-2001 08:20", "format_value function");
+ ok ( $str eq "Tue Sep 11 08:20:00 2001", "Perl representation of time");
+}
+
+
+# Check that attempting to open a non-existent file results in an error
+{
+  my $tempdir = tempdir( CLEANUP => 1 );
+
+  unlink ("$tempdir/no-such-file.sav");
+
+  my $sf = PSPP::Reader->open ("$tempdir/no-such-file.sav");
+
+  ok ( !ref $sf, "Returns undef on opening failure");
+
+  ok ("$PSPP::errstr" eq "Error opening \"$tempdir/no-such-file.sav\" for reading as a system file: No such file or directory.",
+      "Error string on open failure");
+}
+
+
+# Missing value tests. 
+{
+ my $tempdir = tempdir( CLEANUP => 1 );
+
+ generate_sav_file ("$tempdir/in.sav", "$tempdir");
+
+ my $sf = PSPP::Reader->open ("$tempdir/in.sav");
+
+ my $dict = $sf->get_dict ();
+
+
+ my (@c) = $sf->get_next_case ();
+
+ my $stringvar = $dict->get_var (0);
+ my $numericvar = $dict->get_var (2);
+ my $val = $c[0];
+
+ ok ( !PSPP::value_is_missing ($val, $stringvar), "Missing Value Negative String");
+
+ $val = $c[2];
+
+ ok ( !PSPP::value_is_missing ($val, $numericvar), "Missing Value Negative Num");
+
+ @c = $sf->get_next_case (); 
+ @c = $sf->get_next_case (); 
+
+ $val = $c[0];
+ ok ( PSPP::value_is_missing ($val, $stringvar), "Missing Value Positive");
+
+ @c = $sf->get_next_case (); 
+ $val = $c[2];
+ ok ( PSPP::value_is_missing ($val, $numericvar), "Missing Value Positive SYS");
+
+ @c = $sf->get_next_case (); 
+ $val = $c[2];
+ ok ( PSPP::value_is_missing ($val, $numericvar), "Missing Value Positive Num");
+}
+
+
+#Test reading of custom attributes
+{
+    my $tempdir = tempdir( CLEANUP => 1 );
+
+    generate_sav_file ("$tempdir/in.sav", "$tempdir");
+
+    my $sf = PSPP::Reader->open ("$tempdir/in.sav");
+
+    my $dict = $sf->get_dict ();
+
+    my $var = $dict->get_var_by_name ("numeric");
+
+    my $attr = $var->get_attributes ();
+
+    open (MYFILE, ">$tempdir/out.txt");
+
+    foreach $k (keys %$attr)
+    {
+       my $ll = $attr->{$k};
+       print MYFILE "$k =>";
+       print MYFILE map "$_\n", join ', ', @$ll;
+    }
+
+    close (MYFILE);
+
+    ok (compare ("$tempdir/out.txt", <<EOF), "Custom Attributes");
+colour =>blue, pink, violet
+nationality =>foreign
+size =>large
+EOF
+
+}
diff --git a/perl-module/typemap b/perl-module/typemap
new file mode 100644 (file)
index 0000000..cd45c33
--- /dev/null
@@ -0,0 +1,53 @@
+TYPEMAP
+ struct dictionary *   T_PTRREF
+ struct variable *     T_PTRREF
+ struct sysfile_info * T_PTRREF
+ struct sysreader_info * T_PTRREF
+ input_format  INPUT_FMT_SPEC
+ output_format OUTPUT_FMT_SPEC
+
+
+INPUT
+OUTPUT_FMT_SPEC
+ {
+   HV *hv = (HV *) SvRV ($arg);
+   SV** the_format = hv_fetch (hv, \"fmt\", 3, 0);
+   SV** decimals = hv_fetch (hv, \"decimals\", 8, 0);
+   SV** width = hv_fetch (hv, \"width\", 5, 0);
+
+   $var.type = the_format ? SvIV (*the_format) : FMT_F;
+   $var.w    = width ? SvIV (*width) : 8;
+   $var.d    = decimals ? SvIV (*decimals) :
+     fmt_takes_decimals ($var.type) ?
+     MIN (2, fmt_max_output_decimals ($var.type, $var.w)) : 0;
+   if ( ! fmt_check_output (&$var))
+   {
+       char buf[FMT_STRING_LEN_MAX + 1];
+        fmt_to_string (&$var, buf);
+       croak (\"%s is an invalid output format\", buf);
+   }
+
+ }
+
+
+INPUT_FMT_SPEC
+ {
+   HV *hv = (HV *) SvRV ($arg);
+   SV** the_format = hv_fetch (hv, \"fmt\", 3, 0);
+   SV** decimals = hv_fetch (hv, \"decimals\", 8, 0);
+   SV** width = hv_fetch (hv, \"width\", 5, 0);
+
+
+   $var.type = the_format ? SvIV (*the_format) : FMT_F;
+   $var.w    = width ? SvIV (*width) : 8;
+   $var.d    = decimals ? SvIV (*decimals) :
+     fmt_takes_decimals ($var.type) ?
+     MIN (2, fmt_max_input_decimals ($var.type, $var.w)) : 0;
+   if ( ! fmt_check_input (&$var))
+   {
+       char buf[FMT_STRING_LEN_MAX + 1];
+        fmt_to_string (&$var, buf);
+       croak (\"%s is an invalid input format\", buf);
+   }
+
+ }
index 29e13a536b8414c59560308f5efefd8ebb70d7b1..6f2af173e2ce3cf41935de8de653a6d6c1d16337 100644 (file)
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PSPP 0.7.0\n"
 "Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
-"POT-Creation-Date: 2008-12-14 11:19+0900\n"
+"POT-Creation-Date: 2009-01-08 16:40+0900\n"
 "PO-Revision-Date: 2008-11-05 08:17+0900\n"
 "Last-Translator: John Darrington <john@darrington.wattle.id.au>\n"
 "Language-Team: John Darrington <john@darrington.wattle.id.au>\n"
@@ -323,13 +323,13 @@ msgid "%s variables are not compatible with %s format %s."
 msgstr ""
 
 #: src/data/format.c:327 src/data/sys-file-reader.c:655
-#: src/ui/gui/data-editor.glade:1197 src/ui/gui/psppire.glade:2176
+#: src/ui/gui/data-editor.glade:1197 src/ui/gui/psppire.glade:2136
 #: src/ui/gui/psppire-var-store.c:557
 msgid "String"
 msgstr ""
 
 #: src/data/format.c:327 src/data/sys-file-reader.c:655
-#: src/ui/gui/data-editor.glade:1086 src/ui/gui/psppire.glade:2131
+#: src/ui/gui/data-editor.glade:1086 src/ui/gui/psppire.glade:2211
 #: src/ui/gui/psppire-var-store.c:550
 msgid "Numeric"
 msgstr ""
@@ -362,22 +362,22 @@ msgid ""
 "Support for Gnumeric files was not compiled into this installation of PSPP"
 msgstr ""
 
-#: src/data/gnumeric-reader.c:366
+#: src/data/gnumeric-reader.c:365
 #, c-format
 msgid "Error opening \"%s\" for reading as a gnumeric file: %s."
 msgstr ""
 
-#: src/data/gnumeric-reader.c:386
+#: src/data/gnumeric-reader.c:385
 #, c-format
 msgid "Invalid cell range \"%s\""
 msgstr ""
 
-#: src/data/gnumeric-reader.c:523 src/data/psql-reader.c:184
+#: src/data/gnumeric-reader.c:522 src/data/psql-reader.c:182
 #, c-format
 msgid "Cannot create variable name from %s"
 msgstr ""
 
-#: src/data/gnumeric-reader.c:535
+#: src/data/gnumeric-reader.c:534
 #, c-format
 msgid "Selected sheet or range of spreadsheet \"%s\" is empty."
 msgstr ""
@@ -596,35 +596,35 @@ msgid ""
 "installation of PSPP"
 msgstr ""
 
-#: src/data/psql-reader.c:239
+#: src/data/psql-reader.c:237
 msgid "Memory error whilst opening psql source"
 msgstr ""
 
-#: src/data/psql-reader.c:245
+#: src/data/psql-reader.c:243
 #, c-format
 msgid "Error opening psql source: %s."
 msgstr ""
 
-#: src/data/psql-reader.c:260
+#: src/data/psql-reader.c:258
 #, c-format
 msgid ""
 "Postgres server is version %s. Reading from versions earlier than 8.0 is not "
 "supported."
 msgstr ""
 
-#: src/data/psql-reader.c:280
+#: src/data/psql-reader.c:278
 msgid ""
 "Connection is unencrypted, but unencrypted connections have not been "
 "permitted."
 msgstr ""
 
-#: src/data/psql-reader.c:307 src/data/psql-reader.c:332
-#: src/data/psql-reader.c:342
+#: src/data/psql-reader.c:305 src/data/psql-reader.c:330
+#: src/data/psql-reader.c:340
 #, c-format
 msgid "Error from psql source: %s."
 msgstr ""
 
-#: src/data/psql-reader.c:437
+#: src/data/psql-reader.c:435
 #, c-format
 msgid "Unsupported OID %d.  SYSMIS values will be inserted."
 msgstr ""
@@ -655,7 +655,7 @@ msgstr ""
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/sys-file-reader.c:214 src/data/sys-file-writer.c:196
+#: src/data/sys-file-reader.c:214 src/data/sys-file-writer.c:197
 msgid "system file"
 msgstr ""
 
@@ -976,43 +976,43 @@ msgstr ""
 msgid "Unexpected end of file."
 msgstr ""
 
-#: src/data/sys-file-writer.c:169
+#: src/data/sys-file-writer.c:170
 #, c-format
 msgid "Unknown system file version %d. Treating as version %d."
 msgstr ""
 
-#: src/data/sys-file-writer.c:208
+#: src/data/sys-file-writer.c:209
 #, c-format
 msgid "Error opening \"%s\" for writing as a system file: %s."
 msgstr ""
 
-#: src/data/sys-file-writer.c:813
+#: src/data/sys-file-writer.c:814
 #, c-format
 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 ""
@@ -1287,7 +1287,7 @@ msgid ""
 "name."
 msgstr ""
 
-#: src/language/data-io/combine-files.c:738
+#: src/language/data-io/combine-files.c:737
 #, c-format
 msgid "Encountered %zu sets of duplicate cases in the master file."
 msgstr ""
@@ -1333,65 +1333,65 @@ msgstr ""
 msgid "Cannot place variable %s on record %d when RECORDS=%d is specified."
 msgstr ""
 
-#: src/language/data-io/data-parser.c:455
-#: src/language/data-io/data-parser.c:464
+#: src/language/data-io/data-parser.c:458
+#: src/language/data-io/data-parser.c:467
 msgid "Quoted string extends beyond end of line."
 msgstr ""
 
-#: src/language/data-io/data-parser.c:519
+#: src/language/data-io/data-parser.c:522
 #, c-format
 msgid "Partial case of %d of %d records discarded."
 msgstr ""
 
-#: src/language/data-io/data-parser.c:565
+#: src/language/data-io/data-parser.c:568
 #, c-format
 msgid "Partial case discarded.  The first variable missing was %s."
 msgstr ""
 
-#: src/language/data-io/data-parser.c:602
+#: src/language/data-io/data-parser.c:605
 #, c-format
 msgid ""
 "Missing value(s) for all variables from %s onward.  These will be filled "
 "with the system-missing value or blanks, as appropriate."
 msgstr ""
 
-#: src/language/data-io/data-parser.c:621
+#: src/language/data-io/data-parser.c:624
 msgid "Record ends in data not part of any field."
 msgstr ""
 
-#: src/language/data-io/data-parser.c:641
-#: src/language/data-io/data-parser.c:682 src/language/data-io/print.c:403
+#: src/language/data-io/data-parser.c:644
+#: src/language/data-io/data-parser.c:685 src/language/data-io/print.c:403
 #: src/language/dictionary/split-file.c:84
 #: src/language/dictionary/sys-file-info.c:162
 #: src/language/dictionary/sys-file-info.c:386
 #: src/language/dictionary/sys-file-info.c:709
-#: src/language/stats/descriptives.c:883 src/ui/gui/dict-display.c:245
+#: src/language/stats/descriptives.c:885 src/ui/gui/dict-display.c:245
 msgid "Variable"
 msgstr ""
 
-#: src/language/data-io/data-parser.c:642 src/language/data-io/print.c:404
+#: src/language/data-io/data-parser.c:645 src/language/data-io/print.c:404
 msgid "Record"
 msgstr ""
 
-#: src/language/data-io/data-parser.c:643 src/language/data-io/print.c:405
+#: src/language/data-io/data-parser.c:646 src/language/data-io/print.c:405
 #: src/ui/gui/crosstabs.glade:92 src/ui/gui/psppire-var-sheet.c:517
 #: src/ui/gui/psppire-var-store.c:770
 msgid "Columns"
 msgstr ""
 
-#: src/language/data-io/data-parser.c:644
-#: src/language/data-io/data-parser.c:683 src/language/data-io/print.c:406
+#: src/language/data-io/data-parser.c:647
+#: src/language/data-io/data-parser.c:686 src/language/data-io/print.c:406
 msgid "Format"
 msgstr ""
 
-#: src/language/data-io/data-parser.c:663
+#: src/language/data-io/data-parser.c:666
 #, c-format
 msgid "Reading %d record from %s."
 msgid_plural "Reading %d records from %s."
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/language/data-io/data-parser.c:699
+#: src/language/data-io/data-parser.c:702
 #, c-format
 msgid "Reading free-form data from %s."
 msgstr ""
@@ -1587,11 +1587,11 @@ msgstr ""
 msgid "Input program did not create any variables."
 msgstr ""
 
-#: src/language/data-io/inpt-pgm.c:287
+#: src/language/data-io/inpt-pgm.c:286
 msgid "COLUMN subcommand multiply specified."
 msgstr ""
 
-#: src/language/data-io/inpt-pgm.c:337
+#: src/language/data-io/inpt-pgm.c:336
 msgid ""
 "REREAD: Column numbers must be positive finite numbers.  Column set to 1."
 msgstr ""
@@ -1628,7 +1628,7 @@ msgstr ""
 msgid "`/FORMAT WEIGHT' specified, but weighting is not on."
 msgstr ""
 
-#: src/language/data-io/list.q:467
+#: src/language/data-io/list.q:468
 msgid "Line"
 msgstr ""
 
@@ -1792,7 +1792,7 @@ msgid "`)' expected after output format."
 msgstr ""
 
 #: src/language/dictionary/missing-values.c:56
-#: src/language/stats/aggregate.c:459
+#: src/language/stats/aggregate.c:458
 msgid "expecting `('"
 msgstr ""
 
@@ -1927,10 +1927,10 @@ msgstr ""
 #: src/language/dictionary/split-file.c:85
 #: src/language/dictionary/sys-file-info.c:480
 #: src/language/dictionary/sys-file-info.c:629
-#: src/language/stats/crosstabs.q:1155 src/language/stats/crosstabs.q:1182
-#: src/language/stats/crosstabs.q:1202 src/language/stats/crosstabs.q:1224
-#: src/language/stats/examine.q:1939 src/language/stats/frequencies.q:1055
-#: src/language/stats/frequencies.q:1179 src/language/stats/reliability.q:572
+#: src/language/stats/crosstabs.q:1156 src/language/stats/crosstabs.q:1183
+#: src/language/stats/crosstabs.q:1203 src/language/stats/crosstabs.q:1225
+#: src/language/stats/examine.q:1941 src/language/stats/frequencies.q:1056
+#: src/language/stats/frequencies.q:1180 src/language/stats/reliability.q:572
 #: src/language/stats/reliability.q:583
 msgid "Value"
 msgstr ""
@@ -1938,7 +1938,7 @@ msgstr ""
 #: src/language/dictionary/split-file.c:86
 #: src/language/dictionary/sys-file-info.c:390
 #: src/language/dictionary/sys-file-info.c:630 src/ui/gui/crosstabs.glade:275
-#: src/ui/gui/psppire.glade:2099 src/ui/gui/psppire-var-sheet.c:514
+#: src/ui/gui/psppire.glade:2101 src/ui/gui/psppire-var-sheet.c:514
 #: src/ui/gui/psppire-var-store.c:767
 msgid "Label"
 msgstr ""
@@ -1947,7 +1947,7 @@ msgstr ""
 msgid "File:"
 msgstr ""
 
-#: src/language/dictionary/sys-file-info.c:115 src/ui/gui/psppire.glade:2052
+#: src/language/dictionary/sys-file-info.c:115 src/ui/gui/psppire.glade:2040
 #: src/ui/gui/recode.glade:841
 msgid "Label:"
 msgstr ""
@@ -2336,7 +2336,7 @@ msgstr ""
 msgid "Unknown identifier %s."
 msgstr ""
 
-#: src/language/expressions/parse.c:885 src/language/stats/aggregate.c:517
+#: src/language/expressions/parse.c:885 src/language/stats/aggregate.c:516
 msgid "expecting `)'"
 msgstr ""
 
@@ -2621,40 +2621,40 @@ msgid ""
 "has no effect.  Output data will be sorted the same way as the input data."
 msgstr ""
 
-#: src/language/stats/aggregate.c:424
+#: src/language/stats/aggregate.c:423
 msgid "expecting aggregation function"
 msgstr ""
 
-#: src/language/stats/aggregate.c:442
+#: src/language/stats/aggregate.c:441
 #, c-format
 msgid "Unknown aggregation function %s."
 msgstr ""
 
-#: src/language/stats/aggregate.c:498
+#: src/language/stats/aggregate.c:497
 #, c-format
 msgid "Missing argument %zu to %s."
 msgstr ""
 
-#: src/language/stats/aggregate.c:507
+#: src/language/stats/aggregate.c:506
 #, c-format
 msgid "Arguments to %s must be of same type as source variables."
 msgstr ""
 
-#: src/language/stats/aggregate.c:529
+#: src/language/stats/aggregate.c:528
 #, c-format
 msgid ""
 "Number of source variables (%zu) does not match number of target variables (%"
 "zu)."
 msgstr ""
 
-#: src/language/stats/aggregate.c:545
+#: src/language/stats/aggregate.c:544
 #, c-format
 msgid ""
 "The value arguments passed to the %s function are out-of-order.  They will "
 "be treated as if they had been specified in the correct order."
 msgstr ""
 
-#: src/language/stats/aggregate.c:615
+#: src/language/stats/aggregate.c:614
 #, c-format
 msgid ""
 "Variable name %s is not unique within the aggregate file dictionary, which "
@@ -2694,26 +2694,26 @@ msgid "Group2"
 msgstr ""
 
 #: src/language/stats/binomial.c:205 src/language/stats/chisquare.c:223
-#: src/language/stats/chisquare.c:283 src/language/stats/crosstabs.q:862
-#: src/language/stats/crosstabs.q:1062 src/language/stats/crosstabs.q:1785
-#: src/language/stats/examine.q:1198 src/language/stats/frequencies.q:1132
+#: src/language/stats/chisquare.c:283 src/language/stats/crosstabs.q:863
+#: src/language/stats/crosstabs.q:1063 src/language/stats/crosstabs.q:1786
+#: src/language/stats/examine.q:1200 src/language/stats/frequencies.q:1133
 #: src/language/stats/oneway.q:304 src/language/stats/oneway.q:470
 #: src/language/stats/regression.q:309 src/language/stats/reliability.q:705
-#: src/language/stats/wilcoxon.c:246 src/ui/gui/crosstabs-dialog.c:59
+#: src/language/stats/wilcoxon.c:240 src/ui/gui/crosstabs-dialog.c:59
 msgid "Total"
 msgstr ""
 
 #: src/language/stats/binomial.c:237 src/language/stats/chisquare.c:246
-#: src/language/stats/crosstabs.q:1180 src/language/stats/crosstabs.q:1221
+#: src/language/stats/crosstabs.q:1181 src/language/stats/crosstabs.q:1222
 msgid "Category"
 msgstr ""
 
-#: src/language/stats/binomial.c:238 src/language/stats/crosstabs.q:872
-#: src/language/stats/examine.q:1271 src/language/stats/frequencies.q:1400
+#: src/language/stats/binomial.c:238 src/language/stats/crosstabs.q:873
+#: src/language/stats/examine.q:1273 src/language/stats/frequencies.q:1401
 #: src/language/stats/npar-summary.c:122 src/language/stats/oneway.q:386
 #: src/language/stats/reliability.q:708 src/language/stats/t-test.q:693
 #: src/language/stats/t-test.q:716 src/language/stats/t-test.q:850
-#: src/language/stats/t-test.q:1387 src/language/stats/wilcoxon.c:229
+#: src/language/stats/t-test.q:1387 src/language/stats/wilcoxon.c:223
 msgid "N"
 msgstr ""
 
@@ -2754,7 +2754,7 @@ msgstr ""
 msgid "Frequencies"
 msgstr ""
 
-#: src/language/stats/chisquare.c:297 src/language/stats/wilcoxon.c:297
+#: src/language/stats/chisquare.c:297 src/language/stats/wilcoxon.c:291
 msgid "Test Statistics"
 msgstr ""
 
@@ -2762,7 +2762,7 @@ msgstr ""
 msgid "Chi-Square"
 msgstr ""
 
-#: src/language/stats/chisquare.c:312 src/language/stats/crosstabs.q:1156
+#: src/language/stats/chisquare.c:312 src/language/stats/crosstabs.q:1157
 #: src/language/stats/oneway.q:277 src/language/stats/oneway.q:683
 #: src/language/stats/regression.q:302 src/language/stats/t-test.q:1001
 #: src/language/stats/t-test.q:1193 src/language/stats/t-test.q:1286
@@ -2799,262 +2799,262 @@ msgstr ""
 msgid "Maximum value (%ld) less than minimum value (%ld)."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:857
+#: src/language/stats/crosstabs.q:858
 msgid "Summary."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:859 src/language/stats/examine.q:1259
+#: src/language/stats/crosstabs.q:860 src/language/stats/examine.q:1261
 #: src/language/stats/reliability.q:696
 msgid "Cases"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:860 src/language/stats/examine.q:1196
-#: src/language/stats/frequencies.q:1053 src/language/stats/frequencies.q:1401
+#: src/language/stats/crosstabs.q:861 src/language/stats/examine.q:1198
+#: src/language/stats/frequencies.q:1054 src/language/stats/frequencies.q:1402
 #: src/language/stats/reliability.q:699
 msgid "Valid"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:861 src/language/stats/examine.q:1197
-#: src/language/stats/frequencies.q:1123 src/language/stats/frequencies.q:1402
+#: src/language/stats/crosstabs.q:862 src/language/stats/examine.q:1199
+#: src/language/stats/frequencies.q:1124 src/language/stats/frequencies.q:1403
 #: src/ui/gui/psppire-var-sheet.c:516 src/ui/gui/psppire-var-store.c:769
 msgid "Missing"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:873 src/language/stats/examine.q:1274
-#: src/language/stats/frequencies.q:1057 src/language/stats/frequencies.q:1058
-#: src/language/stats/frequencies.q:1059
+#: src/language/stats/crosstabs.q:874 src/language/stats/examine.q:1276
+#: src/language/stats/frequencies.q:1058 src/language/stats/frequencies.q:1059
+#: src/language/stats/frequencies.q:1060
 msgid "Percent"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1114
+#: src/language/stats/crosstabs.q:1115
 msgid "count"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1115
+#: src/language/stats/crosstabs.q:1116
 msgid "row %"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1116
+#: src/language/stats/crosstabs.q:1117
 msgid "column %"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1117
+#: src/language/stats/crosstabs.q:1118
 msgid "total %"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1118
+#: src/language/stats/crosstabs.q:1119
 msgid "expected"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1119
+#: src/language/stats/crosstabs.q:1120
 msgid "residual"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1120
+#: src/language/stats/crosstabs.q:1121
 msgid "std. resid."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1121
+#: src/language/stats/crosstabs.q:1122
 msgid "adj. resid."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1151
+#: src/language/stats/crosstabs.q:1152
 msgid "Chi-square tests."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1154 src/language/stats/crosstabs.q:1181
-#: src/language/stats/crosstabs.q:1201 src/language/stats/crosstabs.q:1222
-#: src/language/stats/examine.q:1736 src/ui/gui/checkbox-treeview.c:94
+#: src/language/stats/crosstabs.q:1155 src/language/stats/crosstabs.q:1182
+#: src/language/stats/crosstabs.q:1202 src/language/stats/crosstabs.q:1223
+#: src/language/stats/examine.q:1738 src/ui/gui/checkbox-treeview.c:94
 msgid "Statistic"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1158
+#: src/language/stats/crosstabs.q:1159
 msgid "Asymp. Sig. (2-sided)"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1160
+#: src/language/stats/crosstabs.q:1161
 msgid "Exact. Sig. (2-sided)"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1162
+#: src/language/stats/crosstabs.q:1163
 msgid "Exact. Sig. (1-sided)"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1177
+#: src/language/stats/crosstabs.q:1178
 msgid "Symmetric measures."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1183 src/language/stats/crosstabs.q:1225
+#: src/language/stats/crosstabs.q:1184 src/language/stats/crosstabs.q:1226
 msgid "Asymp. Std. Error"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1184 src/language/stats/crosstabs.q:1226
+#: src/language/stats/crosstabs.q:1185 src/language/stats/crosstabs.q:1227
 msgid "Approx. T"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1185 src/language/stats/crosstabs.q:1227
+#: src/language/stats/crosstabs.q:1186 src/language/stats/crosstabs.q:1228
 msgid "Approx. Sig."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1196
+#: src/language/stats/crosstabs.q:1197
 msgid "Risk estimate."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1200
+#: src/language/stats/crosstabs.q:1201
 #, c-format
 msgid "95%% Confidence Interval"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1203 src/language/stats/t-test.q:1005
+#: src/language/stats/crosstabs.q:1204 src/language/stats/t-test.q:1005
 #: src/language/stats/t-test.q:1190 src/language/stats/t-test.q:1289
 msgid "Lower"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1204 src/language/stats/t-test.q:1006
+#: src/language/stats/crosstabs.q:1205 src/language/stats/t-test.q:1006
 #: src/language/stats/t-test.q:1191 src/language/stats/t-test.q:1290
 msgid "Upper"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1218
+#: src/language/stats/crosstabs.q:1219
 msgid "Directional measures."
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1223 src/ui/gui/psppire.glade:2223
+#: src/language/stats/crosstabs.q:1224 src/ui/gui/psppire.glade:2226
 #: src/ui/gui/psppire-var-sheet.c:511 src/ui/gui/psppire-var-store.c:764
 msgid "Type"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1976
+#: src/language/stats/crosstabs.q:1977
 msgid "Pearson Chi-Square"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1977
+#: src/language/stats/crosstabs.q:1978
 msgid "Likelihood Ratio"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1978
+#: src/language/stats/crosstabs.q:1979
 msgid "Fisher's Exact Test"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1979
+#: src/language/stats/crosstabs.q:1980
 msgid "Continuity Correction"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:1980
+#: src/language/stats/crosstabs.q:1981
 msgid "Linear-by-Linear Association"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2017 src/language/stats/crosstabs.q:2087
-#: src/language/stats/crosstabs.q:2146
+#: src/language/stats/crosstabs.q:2018 src/language/stats/crosstabs.q:2088
+#: src/language/stats/crosstabs.q:2147
 msgid "N of Valid Cases"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2033 src/language/stats/crosstabs.q:2162
+#: src/language/stats/crosstabs.q:2034 src/language/stats/crosstabs.q:2163
 msgid "Nominal by Nominal"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2034 src/language/stats/crosstabs.q:2163
+#: src/language/stats/crosstabs.q:2035 src/language/stats/crosstabs.q:2164
 msgid "Ordinal by Ordinal"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2035
+#: src/language/stats/crosstabs.q:2036
 msgid "Interval by Interval"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2036
+#: src/language/stats/crosstabs.q:2037
 msgid "Measure of Agreement"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2041 src/ui/gui/crosstabs-dialog.c:41
+#: src/language/stats/crosstabs.q:2042 src/ui/gui/crosstabs-dialog.c:41
 msgid "Phi"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2042
+#: src/language/stats/crosstabs.q:2043
 msgid "Cramer's V"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2043
+#: src/language/stats/crosstabs.q:2044
 msgid "Contingency Coefficient"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2044
+#: src/language/stats/crosstabs.q:2045
 msgid "Kendall's tau-b"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2045
+#: src/language/stats/crosstabs.q:2046
 msgid "Kendall's tau-c"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2046 src/ui/gui/crosstabs-dialog.c:48
+#: src/language/stats/crosstabs.q:2047 src/ui/gui/crosstabs-dialog.c:48
 msgid "Gamma"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2047
+#: src/language/stats/crosstabs.q:2048
 msgid "Spearman Correlation"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2048
+#: src/language/stats/crosstabs.q:2049
 msgid "Pearson's R"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2049 src/ui/gui/crosstabs-dialog.c:50
+#: src/language/stats/crosstabs.q:2050 src/ui/gui/crosstabs-dialog.c:50
 msgid "Kappa"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2119
+#: src/language/stats/crosstabs.q:2120
 #, c-format
 msgid "Odds Ratio for %s (%g / %g)"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2122
+#: src/language/stats/crosstabs.q:2123
 #, c-format
 msgid "Odds Ratio for %s (%.*s / %.*s)"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2130
+#: src/language/stats/crosstabs.q:2131
 #, c-format
 msgid "For cohort %s = %g"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2133
+#: src/language/stats/crosstabs.q:2134
 #, c-format
 msgid "For cohort %s = %.*s"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2164
+#: src/language/stats/crosstabs.q:2165
 msgid "Nominal by Interval"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2169 src/ui/gui/crosstabs-dialog.c:43
+#: src/language/stats/crosstabs.q:2170 src/ui/gui/crosstabs-dialog.c:43
 msgid "Lambda"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2170
+#: src/language/stats/crosstabs.q:2171
 msgid "Goodman and Kruskal tau"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2171
+#: src/language/stats/crosstabs.q:2172
 msgid "Uncertainty Coefficient"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2172
+#: src/language/stats/crosstabs.q:2173
 msgid "Somers' d"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2173 src/ui/gui/crosstabs-dialog.c:51
+#: src/language/stats/crosstabs.q:2174 src/ui/gui/crosstabs-dialog.c:51
 msgid "Eta"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2178
+#: src/language/stats/crosstabs.q:2179
 msgid "Symmetric"
 msgstr ""
 
-#: src/language/stats/crosstabs.q:2179 src/language/stats/crosstabs.q:2180
+#: src/language/stats/crosstabs.q:2180 src/language/stats/crosstabs.q:2181
 #, c-format
 msgid "%s Dependent"
 msgstr ""
 
-#: src/language/stats/descriptives.c:102 src/language/stats/examine.q:1541
+#: src/language/stats/descriptives.c:102 src/language/stats/examine.q:1543
 #: src/language/stats/frequencies.q:123 src/language/stats/npar-summary.c:125
 #: src/language/stats/oneway.q:387 src/language/stats/t-test.q:694
 #: src/language/stats/t-test.q:717 src/language/stats/t-test.q:849
@@ -3071,13 +3071,13 @@ msgstr ""
 msgid "Std Dev"
 msgstr ""
 
-#: src/language/stats/descriptives.c:105 src/language/stats/examine.q:1572
+#: src/language/stats/descriptives.c:105 src/language/stats/examine.q:1574
 #: src/language/stats/frequencies.q:128 src/ui/gui/descriptives-dialog.c:46
 #: src/ui/gui/frequencies-dialog.c:45
 msgid "Variance"
 msgstr ""
 
-#: src/language/stats/descriptives.c:106 src/language/stats/examine.q:1608
+#: src/language/stats/descriptives.c:106 src/language/stats/examine.q:1610
 #: src/language/stats/frequencies.q:129 src/ui/gui/descriptives-dialog.c:47
 #: src/ui/gui/frequencies-dialog.c:50
 msgid "Kurtosis"
@@ -3087,7 +3087,7 @@ msgstr ""
 msgid "S E Kurt"
 msgstr ""
 
-#: src/language/stats/descriptives.c:108 src/language/stats/examine.q:1603
+#: src/language/stats/descriptives.c:108 src/language/stats/examine.q:1605
 #: src/language/stats/frequencies.q:131 src/ui/gui/descriptives-dialog.c:48
 #: src/ui/gui/frequencies-dialog.c:46
 msgid "Skewness"
@@ -3097,20 +3097,20 @@ msgstr ""
 msgid "S E Skew"
 msgstr ""
 
-#: src/language/stats/descriptives.c:110 src/language/stats/examine.q:1592
+#: src/language/stats/descriptives.c:110 src/language/stats/examine.q:1594
 #: src/language/stats/frequencies.q:133 src/ui/gui/descriptives-dialog.c:43
 #: src/ui/gui/frequencies-dialog.c:48
 msgid "Range"
 msgstr ""
 
-#: src/language/stats/descriptives.c:111 src/language/stats/examine.q:1582
+#: src/language/stats/descriptives.c:111 src/language/stats/examine.q:1584
 #: src/language/stats/frequencies.q:134 src/language/stats/npar-summary.c:131
 #: src/language/stats/oneway.q:400 src/ui/gui/descriptives-dialog.c:41
 #: src/ui/gui/frequencies-dialog.c:42
 msgid "Minimum"
 msgstr ""
 
-#: src/language/stats/descriptives.c:112 src/language/stats/examine.q:1587
+#: src/language/stats/descriptives.c:112 src/language/stats/examine.q:1589
 #: src/language/stats/frequencies.q:135 src/language/stats/npar-summary.c:134
 #: src/language/stats/oneway.q:401 src/ui/gui/descriptives-dialog.c:42
 #: src/ui/gui/frequencies-dialog.c:43
@@ -3149,26 +3149,26 @@ msgstr ""
 msgid "Target"
 msgstr ""
 
-#: src/language/stats/descriptives.c:672
+#: src/language/stats/descriptives.c:673
 #, c-format
 msgid "Z-score of %s"
 msgstr ""
 
-#: src/language/stats/descriptives.c:886
+#: src/language/stats/descriptives.c:888
 msgid "Valid N"
 msgstr ""
 
-#: src/language/stats/descriptives.c:887
+#: src/language/stats/descriptives.c:889
 msgid "Missing N"
 msgstr ""
 
-#: src/language/stats/descriptives.c:914
+#: src/language/stats/descriptives.c:916
 #, c-format
 msgid "Valid cases = %g; cases with missing value(s) = %g."
 msgstr ""
 
 #: src/language/stats/examine.q:337 src/language/stats/examine.q:490
-#: src/language/stats/examine.q:1047
+#: src/language/stats/examine.q:1048
 msgid "Not creating plot because data set is empty."
 msgstr ""
 
@@ -3209,55 +3209,55 @@ msgstr ""
 msgid "%s and %s are mutually exclusive"
 msgstr ""
 
-#: src/language/stats/examine.q:1254 src/language/stats/reliability.q:673
+#: src/language/stats/examine.q:1256 src/language/stats/reliability.q:673
 msgid "Case Processing Summary"
 msgstr ""
 
-#: src/language/stats/examine.q:1546 src/language/stats/oneway.q:395
+#: src/language/stats/examine.q:1548 src/language/stats/oneway.q:395
 #, c-format
 msgid "%g%% Confidence Interval for Mean"
 msgstr ""
 
-#: src/language/stats/examine.q:1552 src/language/stats/oneway.q:397
+#: src/language/stats/examine.q:1554 src/language/stats/oneway.q:397
 msgid "Lower Bound"
 msgstr ""
 
-#: src/language/stats/examine.q:1557 src/language/stats/oneway.q:398
+#: src/language/stats/examine.q:1559 src/language/stats/oneway.q:398
 msgid "Upper Bound"
 msgstr ""
 
-#: src/language/stats/examine.q:1562
+#: src/language/stats/examine.q:1564
 #, c-format
 msgid "5%% Trimmed Mean"
 msgstr ""
 
-#: src/language/stats/examine.q:1567 src/language/stats/frequencies.q:125
+#: src/language/stats/examine.q:1569 src/language/stats/frequencies.q:125
 #: src/ui/gui/frequencies-dialog.c:52
 msgid "Median"
 msgstr ""
 
-#: src/language/stats/examine.q:1577 src/language/stats/npar-summary.c:128
+#: src/language/stats/examine.q:1579 src/language/stats/npar-summary.c:128
 #: src/language/stats/oneway.q:388 src/language/stats/t-test.q:695
 #: src/language/stats/t-test.q:718 src/language/stats/t-test.q:851
 #: src/language/stats/t-test.q:1188
 msgid "Std. Deviation"
 msgstr ""
 
-#: src/language/stats/examine.q:1597
+#: src/language/stats/examine.q:1599
 msgid "Interquartile Range"
 msgstr ""
 
-#: src/language/stats/examine.q:1733 src/language/stats/oneway.q:404
-#: src/ui/gui/examine.glade:307
+#: src/language/stats/examine.q:1735 src/language/stats/oneway.q:404
+#: src/ui/gui/examine.glade:310
 msgid "Descriptives"
 msgstr ""
 
-#: src/language/stats/examine.q:1739 src/language/stats/oneway.q:389
+#: src/language/stats/examine.q:1741 src/language/stats/oneway.q:389
 #: src/language/stats/oneway.q:681 src/language/stats/regression.q:203
 msgid "Std. Error"
 msgstr ""
 
-#: src/language/stats/examine.q:1836 src/language/stats/examine.q:1841
+#: src/language/stats/examine.q:1838 src/language/stats/examine.q:1843
 #: src/ui/gui/psppire-data-store.c:749 src/ui/gui/psppire-var-store.c:627
 #: src/ui/gui/psppire-var-store.c:637 src/ui/gui/psppire-var-store.c:647
 #: src/ui/gui/psppire-var-store.c:756
@@ -3265,33 +3265,33 @@ msgstr ""
 msgid "%d"
 msgstr ""
 
-#: src/language/stats/examine.q:1919
+#: src/language/stats/examine.q:1921
 msgid "Highest"
 msgstr ""
 
-#: src/language/stats/examine.q:1924
+#: src/language/stats/examine.q:1926
 msgid "Lowest"
 msgstr ""
 
-#: src/language/stats/examine.q:1931
+#: src/language/stats/examine.q:1933
 msgid "Extreme Values"
 msgstr ""
 
-#: src/language/stats/examine.q:1935
+#: src/language/stats/examine.q:1937
 msgid "Case Number"
 msgstr ""
 
-#: src/language/stats/examine.q:2057
+#: src/language/stats/examine.q:2059
 msgid "Tukey's Hinges"
 msgstr ""
 
-#: src/language/stats/examine.q:2097 src/language/stats/examine.q:2115
-#: src/language/stats/frequencies.q:1412 src/language/stats/npar-summary.c:141
-#: src/ui/gui/examine.glade:328
+#: src/language/stats/examine.q:2099 src/language/stats/examine.q:2117
+#: src/language/stats/frequencies.q:1413 src/language/stats/npar-summary.c:141
+#: src/ui/gui/examine.glade:333
 msgid "Percentiles"
 msgstr ""
 
-#: src/language/stats/examine.q:2104
+#: src/language/stats/examine.q:2106
 #, c-format
 msgid "%g"
 msgstr ""
@@ -3357,12 +3357,12 @@ msgstr ""
 msgid "Error rewinding FLIP source file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:488
+#: src/language/stats/flip.c:487
 #, c-format
 msgid "Error reading FLIP temporary file: %s."
 msgstr ""
 
-#: src/language/stats/flip.c:491
+#: src/language/stats/flip.c:490
 msgid "Unexpected end of file reading FLIP temporary file."
 msgstr ""
 
@@ -3396,52 +3396,52 @@ msgid ""
 "MIN was specified as %g and MAX as %g.  MIN and MAX will be ignored."
 msgstr ""
 
-#: src/language/stats/frequencies.q:754
+#: src/language/stats/frequencies.q:755
 #, c-format
 msgid "Variable %s specified multiple times on VARIABLES subcommand."
 msgstr ""
 
-#: src/language/stats/frequencies.q:817
+#: src/language/stats/frequencies.q:818
 msgid "`)' expected after GROUPED interval list."
 msgstr ""
 
-#: src/language/stats/frequencies.q:829
+#: src/language/stats/frequencies.q:830
 #, c-format
 msgid "Variables %s specified on GROUPED but not on VARIABLES."
 msgstr ""
 
-#: src/language/stats/frequencies.q:836
+#: src/language/stats/frequencies.q:837
 #, c-format
 msgid "Variables %s specified multiple times on GROUPED subcommand."
 msgstr ""
 
-#: src/language/stats/frequencies.q:1054 src/language/stats/frequencies.q:1147
-#: src/language/stats/frequencies.q:1148 src/language/stats/frequencies.q:1182
+#: src/language/stats/frequencies.q:1055 src/language/stats/frequencies.q:1148
+#: src/language/stats/frequencies.q:1149 src/language/stats/frequencies.q:1183
 msgid "Cum"
 msgstr ""
 
-#: src/language/stats/frequencies.q:1056 src/output/charts/plot-hist.c:140
+#: src/language/stats/frequencies.q:1057 src/output/charts/plot-hist.c:140
 msgid "Frequency"
 msgstr ""
 
-#: src/language/stats/frequencies.q:1077
+#: src/language/stats/frequencies.q:1078
 msgid "Value Label"
 msgstr ""
 
-#: src/language/stats/frequencies.q:1180
+#: src/language/stats/frequencies.q:1181
 msgid "Freq"
 msgstr ""
 
-#: src/language/stats/frequencies.q:1181 src/language/stats/frequencies.q:1183
+#: src/language/stats/frequencies.q:1182 src/language/stats/frequencies.q:1184
 msgid "Pct"
 msgstr ""
 
-#: src/language/stats/frequencies.q:1374
+#: src/language/stats/frequencies.q:1375
 #, c-format
 msgid "No valid data for variable %s; statistics not displayed."
 msgstr ""
 
-#: src/language/stats/frequencies.q:1416
+#: src/language/stats/frequencies.q:1417
 msgid "50 (Median)"
 msgstr ""
 
@@ -3449,7 +3449,7 @@ msgstr ""
 msgid "Multivariate GLM not yet supported"
 msgstr ""
 
-#: src/language/stats/glm.q:261 src/language/stats/regression.q:994
+#: src/language/stats/glm.q:262 src/language/stats/regression.q:996
 msgid "No valid data found. This command was skipped."
 msgstr ""
 
@@ -3606,46 +3606,46 @@ msgstr ""
 msgid "%s of %s"
 msgstr ""
 
-#: src/language/stats/rank.q:599
+#: src/language/stats/rank.q:601
 msgid "Cannot create new rank variable.  All candidates in use."
 msgstr ""
 
-#: src/language/stats/rank.q:692
+#: src/language/stats/rank.q:694
 msgid "Variables Created By RANK"
 msgstr ""
 
-#: src/language/stats/rank.q:716
+#: src/language/stats/rank.q:718
 #, c-format
 msgid "%s into %s(%s of %s using %s BY %s)"
 msgstr ""
 
-#: src/language/stats/rank.q:727
+#: src/language/stats/rank.q:729
 #, c-format
 msgid "%s into %s(%s of %s BY %s)"
 msgstr ""
 
-#: src/language/stats/rank.q:741
+#: src/language/stats/rank.q:743
 #, c-format
 msgid "%s into %s(%s of %s using %s)"
 msgstr ""
 
-#: src/language/stats/rank.q:751
+#: src/language/stats/rank.q:753
 #, c-format
 msgid "%s into %s(%s of %s)"
 msgstr ""
 
-#: src/language/stats/rank.q:764
+#: src/language/stats/rank.q:766
 msgid ""
 "FRACTION has been specified, but NORMAL and PROPORTION rank functions have "
 "not been requested.  The FRACTION subcommand will be ignored."
 msgstr ""
 
-#: src/language/stats/rank.q:855
+#: src/language/stats/rank.q:857
 #, c-format
 msgid "Variable %s already exists."
 msgstr ""
 
-#: src/language/stats/rank.q:860
+#: src/language/stats/rank.q:862
 msgid "Too many variables in INTO clause."
 msgstr ""
 
@@ -3701,14 +3701,14 @@ msgstr ""
 msgid "Coefficient Correlations"
 msgstr ""
 
-#: src/language/stats/regression.q:807
+#: src/language/stats/regression.q:808
 msgid ""
 "The dependent variable is equal to the independent variable.The least "
 "squares line is therefore Y=X.Standard errors and related statistics may be "
 "meaningless."
 msgstr ""
 
-#: src/language/stats/regression.q:898
+#: src/language/stats/regression.q:900
 msgid "Dependent variable must be numeric."
 msgstr ""
 
@@ -3927,51 +3927,51 @@ msgstr ""
 msgid "%s & %s"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:216
+#: src/language/stats/wilcoxon.c:210
 msgid "Ranks"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:230
+#: src/language/stats/wilcoxon.c:224
 msgid "Mean Rank"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:231
+#: src/language/stats/wilcoxon.c:225
 msgid "Sum of Ranks"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:243
+#: src/language/stats/wilcoxon.c:237
 msgid "Negative Ranks"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:244
+#: src/language/stats/wilcoxon.c:238
 msgid "Positive Ranks"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:245
+#: src/language/stats/wilcoxon.c:239
 msgid "Ties"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:310
+#: src/language/stats/wilcoxon.c:304
 msgid "Z"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:311
+#: src/language/stats/wilcoxon.c:305
 msgid "Asymp. Sig (2-tailed)"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:315
+#: src/language/stats/wilcoxon.c:309
 msgid "Exact Sig (2-tailed)"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:316
+#: src/language/stats/wilcoxon.c:310
 msgid "Exact Sig (1-tailed)"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:319
+#: src/language/stats/wilcoxon.c:313
 msgid "Point Probability"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:358
+#: src/language/stats/wilcoxon.c:352
 #, c-format
 msgid ""
 "Exact significance was not calculated after %.2f minutes. Skipping test."
@@ -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."
@@ -4233,20 +4238,20 @@ msgstr ""
 msgid "   (Entered %s)"
 msgstr ""
 
-#: src/language/xforms/compute.c:146 src/language/xforms/compute.c:194
+#: src/language/xforms/compute.c:149 src/language/xforms/compute.c:203
 #, c-format
 msgid ""
 "When executing COMPUTE: SYSMIS is not a valid value as an index into vector %"
 "s."
 msgstr ""
 
-#: src/language/xforms/compute.c:150 src/language/xforms/compute.c:201
+#: src/language/xforms/compute.c:153 src/language/xforms/compute.c:210
 #, c-format
 msgid ""
 "When executing COMPUTE: %g is not a valid value as an index into vector %s."
 msgstr ""
 
-#: src/language/xforms/compute.c:344
+#: src/language/xforms/compute.c:354
 #, c-format
 msgid "There is no vector named %s."
 msgstr ""
@@ -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 ""
@@ -4547,7 +4552,7 @@ msgstr ""
 msgid "reading \"%s\""
 msgstr ""
 
-#: src/output/output.c:332 src/ui/gui/message-dialog.c:96
+#: src/output/output.c:332 src/ui/gui/message-dialog.c:95
 #, c-format
 msgid "syntax error"
 msgstr ""
@@ -4745,7 +4750,7 @@ msgid ""
 "bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n"
 msgstr ""
 
-#: src/ui/gui/comments-dialog.c:58
+#: src/ui/gui/comments-dialog.c:57
 #, c-format
 msgid "Column Number: %d"
 msgstr ""
@@ -4820,7 +4825,7 @@ msgstr ""
 msgid "Format..."
 msgstr ""
 
-#: src/ui/gui/crosstabs.glade:138 src/ui/gui/examine.glade:246
+#: src/ui/gui/crosstabs.glade:138 src/ui/gui/examine.glade:247
 #: src/ui/gui/regression.glade:31
 msgid "Statistics..."
 msgstr ""
@@ -4837,7 +4842,7 @@ msgstr ""
 msgid "Pivot"
 msgstr ""
 
-#: src/ui/gui/crosstabs.glade:253 src/ui/gui/psppire.glade:778
+#: src/ui/gui/crosstabs.glade:253 src/ui/gui/psppire.glade:781
 msgid "Ascending"
 msgstr ""
 
@@ -5146,8 +5151,8 @@ msgstr ""
 msgid "Save As"
 msgstr ""
 
-#: src/ui/gui/data-editor.c:1269 src/ui/gui/recode-dialog.c:928
-#: src/ui/gui/recode-dialog.c:1023
+#: src/ui/gui/data-editor.c:1269 src/ui/gui/recode-dialog.c:927
+#: src/ui/gui/recode-dialog.c:1022
 msgid "New"
 msgstr ""
 
@@ -5480,12 +5485,12 @@ msgstr ""
 msgid "Value Label:"
 msgstr ""
 
-#: src/ui/gui/data-editor.glade:1570 src/ui/gui/psppire.glade:2544
+#: src/ui/gui/data-editor.glade:1570 src/ui/gui/psppire.glade:2548
 #: src/ui/gui/recode.glade:185
 msgid "Value:"
 msgstr ""
 
-#: src/ui/gui/data-editor.glade:1707 src/ui/gui/examine.glade:423
+#: src/ui/gui/data-editor.glade:1707 src/ui/gui/examine.glade:432
 #: src/ui/gui/t-test.glade:460
 msgid "Missing Values"
 msgstr ""
@@ -5542,40 +5547,40 @@ msgstr ""
 msgid "Options:"
 msgstr ""
 
-#: src/ui/gui/examine.glade:132
-msgid "Dependent List:"
+#: src/ui/gui/examine.glade:49
+msgid "Label Cases by:"
 msgstr ""
 
-#: src/ui/gui/examine.glade:180
+#: src/ui/gui/examine.glade:100
 msgid "Factor List:"
 msgstr ""
 
-#: src/ui/gui/examine.glade:218
-msgid "Label Cases by:"
+#: src/ui/gui/examine.glade:150
+msgid "Dependent List:"
 msgstr ""
 
-#: src/ui/gui/examine.glade:255 src/ui/gui/t-test.glade:69
+#: src/ui/gui/examine.glade:257 src/ui/gui/t-test.glade:69
 #: src/ui/gui/t-test.glade:629 src/ui/gui/t-test.glade:780
 msgid "Options..."
 msgstr ""
 
-#: src/ui/gui/examine.glade:316
+#: src/ui/gui/examine.glade:320
 msgid "Extremes"
 msgstr ""
 
-#: src/ui/gui/examine.glade:382
+#: src/ui/gui/examine.glade:388
 msgid "Exclude cases listwise"
 msgstr ""
 
-#: src/ui/gui/examine.glade:392
+#: src/ui/gui/examine.glade:399
 msgid "Exclude cases pairwise"
 msgstr ""
 
-#: src/ui/gui/examine.glade:406
+#: src/ui/gui/examine.glade:414
 msgid "Repeat values"
 msgstr ""
 
-#: src/ui/gui/find-dialog.c:659
+#: src/ui/gui/find-dialog.c:658
 #, c-format
 msgid "Bad regular expression: %s"
 msgstr ""
@@ -5592,8 +5597,8 @@ msgstr ""
 msgid "Standard error of the kurtosis"
 msgstr ""
 
-#: src/ui/gui/frequencies.glade:98 src/ui/gui/psppire.glade:265
-#: src/ui/gui/rank.glade:67
+#: src/ui/gui/frequencies.glade:98 src/ui/gui/psppire.glade:277
+#: src/ui/gui/rank.glade:103
 msgid "Variable(s):"
 msgstr ""
 
@@ -5629,11 +5634,11 @@ msgstr ""
 msgid "Maximum no of categories"
 msgstr ""
 
-#: src/ui/gui/helper.c:139
+#: src/ui/gui/helper.c:161
 msgid "Sorry. The help system hasn't yet been implemented."
 msgstr ""
 
-#: src/ui/gui/helper.c:165
+#: src/ui/gui/helper.c:187
 #, c-format
 msgid "Cannot open reference manual: %s"
 msgstr ""
@@ -5654,52 +5659,52 @@ msgstr ""
 msgid "Options affecting syntax and behavior:"
 msgstr "Options affecting syntax and behaviour:"
 
-#: src/ui/gui/message-dialog.c:100
+#: src/ui/gui/message-dialog.c:99
 msgid "data file error"
 msgstr ""
 
-#: src/ui/gui/message-dialog.c:105
+#: src/ui/gui/message-dialog.c:104
 msgid "PSPP error"
 msgstr ""
 
-#: src/ui/gui/message-dialog.c:113
+#: src/ui/gui/message-dialog.c:112
 msgid "syntax warning"
 msgstr ""
 
-#: src/ui/gui/message-dialog.c:117
+#: src/ui/gui/message-dialog.c:116
 msgid "data file warning"
 msgstr ""
 
-#: src/ui/gui/message-dialog.c:122
+#: src/ui/gui/message-dialog.c:121
 msgid "PSPP warning"
 msgstr ""
 
-#: src/ui/gui/message-dialog.c:131
+#: src/ui/gui/message-dialog.c:130
 msgid "syntax information"
 msgstr ""
 
-#: src/ui/gui/message-dialog.c:135
+#: src/ui/gui/message-dialog.c:134
 msgid "data file information"
 msgstr ""
 
-#: src/ui/gui/message-dialog.c:140
+#: src/ui/gui/message-dialog.c:139
 msgid "PSPP information"
 msgstr ""
 
-#: src/ui/gui/message-dialog.c:216
+#: src/ui/gui/message-dialog.c:215
 msgid "The PSPP processing engine reported the following message:"
 msgid_plural "The PSPP processing engine reported the following messages:"
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/ui/gui/message-dialog.c:223
+#: src/ui/gui/message-dialog.c:222
 #, c-format
 msgid "The PSPP processing engine reported %d message."
 msgid_plural "The PSPP processing engine reported %d messages."
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/ui/gui/message-dialog.c:230
+#: src/ui/gui/message-dialog.c:229
 #, c-format
 msgid "%d of these messages are displayed below."
 msgid_plural "%d of these messages are displayed below."
@@ -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 ""
@@ -5847,13 +5852,13 @@ msgstr ""
 msgid "var"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:11
+#: src/ui/gui/psppire.glade:10
 msgid ""
 "This is beta status software.  Please report bugs to bug-gnu-pspp@gnu.org"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:73 src/ui/gui/psppire.glade:154
-#: src/ui/gui/weight-cases-dialog.c:80
+#: src/ui/gui/psppire.glade:72 src/ui/gui/psppire.glade:155
+#: src/ui/gui/weight-cases-dialog.c:79
 msgid "Do not weight cases"
 msgstr ""
 
@@ -5861,15 +5866,15 @@ msgstr ""
 msgid "Weight cases by"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:107
+#: src/ui/gui/psppire.glade:108
 msgid "Frequency Variable"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:147
+#: src/ui/gui/psppire.glade:148
 msgid "Current Status: "
 msgstr ""
 
-#: src/ui/gui/psppire.glade:314
+#: src/ui/gui/psppire.glade:244
 msgid "Name Variable:"
 msgstr ""
 
@@ -5877,195 +5882,181 @@ msgstr ""
 msgid "Analyze all cases.  Do not create groups."
 msgstr "Analyse all cases.  Do not create groups."
 
-#: src/ui/gui/psppire.glade:439
+#: src/ui/gui/psppire.glade:440
 msgid "Compare groups."
 msgstr ""
 
-#: src/ui/gui/psppire.glade:452
+#: src/ui/gui/psppire.glade:454
 msgid "Organize output by groups."
 msgstr "Organise output by groups."
 
-#: src/ui/gui/psppire.glade:499
+#: src/ui/gui/psppire.glade:502
 msgid "Groups based on:"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:563
+#: src/ui/gui/psppire.glade:565
 msgid "Sort the file by grouping variables."
 msgstr ""
 
-#: src/ui/gui/psppire.glade:574
+#: src/ui/gui/psppire.glade:577
 msgid "File is already sorted."
 msgstr ""
 
-#: src/ui/gui/psppire.glade:618
+#: src/ui/gui/psppire.glade:622
 msgid "Current Status : "
 msgstr ""
 
-#: src/ui/gui/psppire.glade:626
+#: src/ui/gui/psppire.glade:630
 msgid "Analysis by groups is off"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:725
+#: src/ui/gui/psppire.glade:729
 msgid "Sort by:"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:788
+#: src/ui/gui/psppire.glade:792
 msgid "Descending"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:804
+#: src/ui/gui/psppire.glade:809
 msgid "Sort Order"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:873
+#: src/ui/gui/psppire.glade:878
 msgid "Target Variable:"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:904
+#: src/ui/gui/psppire.glade:909
 msgid "Type & Label"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:943
+#: src/ui/gui/psppire.glade:949
 msgid "="
 msgstr ""
 
-#: src/ui/gui/psppire.glade:989
+#: src/ui/gui/psppire.glade:995
 msgid "Numeric Expressions:"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1043
+#: src/ui/gui/psppire.glade:1049
 msgid "Functions:"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1107 src/ui/gui/psppire.glade:1253
+#: src/ui/gui/psppire.glade:1112 src/ui/gui/psppire.glade:1516
 #: src/ui/gui/recode.glade:731
 msgid "If..."
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1223
-msgid "All Cases"
+#: src/ui/gui/psppire.glade:1345
+msgid "Use filter variable"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1239
-msgid "If condition is satisfied"
+#: src/ui/gui/psppire.glade:1398
+msgid "Based on time or case range"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1291
-msgid "Random sample of cases"
+#: src/ui/gui/psppire.glade:1411
+msgid "Range..."
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1305
-msgid "Sample..."
+#: src/ui/gui/psppire.glade:1450
+msgid "Random sample of cases"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1343
-msgid "Based on time or case range"
+#: src/ui/gui/psppire.glade:1464
+msgid "Sample..."
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1356
-msgid "Range..."
+#: src/ui/gui/psppire.glade:1502
+msgid "If condition is satisfied"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1394
-msgid "Use filter variable"
+#: src/ui/gui/psppire.glade:1551
+msgid "All Cases"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1556
+#: src/ui/gui/psppire.glade:1566
 msgid "Select"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1586
+#: src/ui/gui/psppire.glade:1595
 msgid "Filtered"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1596
+#: src/ui/gui/psppire.glade:1606
 msgid "Deleted"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1613
+#: src/ui/gui/psppire.glade:1624
 msgid "Unselected Cases Are"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1678
+#: src/ui/gui/psppire.glade:1689
 msgid "Comments:"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1720
+#: src/ui/gui/psppire.glade:1731
 msgid "Display comments in output"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1734
+#: src/ui/gui/psppire.glade:1746
 msgid "Column Number: 0"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1810
+#: src/ui/gui/psppire.glade:1822
 msgid "Variable Information:"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1836
-msgid ""
-"\n"
-"\n"
-"\n"
-"\n"
-"\n"
-"\n"
-"\n"
-"\n"
-"\n"
-"\n"
-msgstr ""
-
-#: src/ui/gui/psppire.glade:1900
-msgid "Observation"
+#: src/ui/gui/psppire.glade:1931
+msgid "First case"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1910
+#: src/ui/gui/psppire.glade:1944
 msgid "Last case"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:1923
-msgid "First case"
+#: src/ui/gui/psppire.glade:1957
+msgid "Observation"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:2081
+#: src/ui/gui/psppire.glade:2021
 msgid "Use expression as label"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:2187 src/ui/gui/psppire-var-sheet.c:512
+#: src/ui/gui/psppire.glade:2147 src/ui/gui/psppire-var-sheet.c:512
 #: src/ui/gui/psppire-var-store.c:765
 msgid "Width"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:2274
+#: src/ui/gui/psppire.glade:2277
 msgid "Goto Case Number:"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:2410
+#: src/ui/gui/psppire.glade:2414
 msgid "Sample Size"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:2513
+#: src/ui/gui/psppire.glade:2517
 msgid "Variable:"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:2570
+#: src/ui/gui/psppire.glade:2574
 msgid "Search value labels"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:2593
+#: src/ui/gui/psppire.glade:2598
 msgid "Regular expression Match"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:2603
+#: src/ui/gui/psppire.glade:2609
 msgid "Search substrings"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:2615
+#: src/ui/gui/psppire.glade:2622
 msgid "Wrap around"
 msgstr ""
 
-#: src/ui/gui/psppire.glade:2627
+#: src/ui/gui/psppire.glade:2635
 msgid "Search backward"
 msgstr ""
 
@@ -6097,56 +6088,56 @@ msgstr ""
 msgid "Custom"
 msgstr ""
 
-#: src/ui/gui/rank.glade:111
+#: src/ui/gui/rank.glade:57
 msgid "By:"
 msgstr ""
 
-#: src/ui/gui/rank.glade:197
+#: src/ui/gui/rank.glade:196
 msgid "_Smallest Value"
 msgstr ""
 
-#: src/ui/gui/rank.glade:209
+#: src/ui/gui/rank.glade:208
 msgid "_Largest Value"
 msgstr ""
 
-#: src/ui/gui/rank.glade:228
+#: src/ui/gui/rank.glade:227
 msgid "Assign rank 1 to:"
 msgstr ""
 
-#: src/ui/gui/rank.glade:246
+#: src/ui/gui/rank.glade:245
 msgid "_Display summary tables"
 msgstr ""
 
-#: src/ui/gui/rank.glade:262
+#: src/ui/gui/rank.glade:261
 msgid "Rank T_ypes"
 msgstr ""
 
-#: src/ui/gui/rank.glade:273
+#: src/ui/gui/rank.glade:272
 msgid "_Ties..."
 msgstr ""
 
-#: src/ui/gui/rank.glade:343
-msgid "Ntiles"
+#: src/ui/gui/rank.glade:339
+msgid "Sum of case weights"
 msgstr ""
 
-#: src/ui/gui/rank.glade:376
-msgid "Rank"
+#: src/ui/gui/rank.glade:355
+msgid "Fractional rank as %"
 msgstr ""
 
-#: src/ui/gui/rank.glade:386
-msgid "Savage score"
+#: src/ui/gui/rank.glade:369
+msgid "Fractional rank"
 msgstr ""
 
-#: src/ui/gui/rank.glade:400
-msgid "Fractional rank"
+#: src/ui/gui/rank.glade:383
+msgid "Savage score"
 msgstr ""
 
-#: src/ui/gui/rank.glade:414
-msgid "Fractional rank as %"
+#: src/ui/gui/rank.glade:397
+msgid "Rank"
 msgstr ""
 
-#: src/ui/gui/rank.glade:428
-msgid "Sum of case weights"
+#: src/ui/gui/rank.glade:411
+msgid "Ntiles"
 msgstr ""
 
 #: src/ui/gui/rank.glade:450
@@ -6157,63 +6148,63 @@ msgstr ""
 msgid "Normal Scores"
 msgstr ""
 
-#: src/ui/gui/rank.glade:495
+#: src/ui/gui/rank.glade:494
 msgid "Blom"
 msgstr ""
 
-#: src/ui/gui/rank.glade:506
+#: src/ui/gui/rank.glade:505
 msgid "Tukey"
 msgstr ""
 
-#: src/ui/gui/rank.glade:520
+#: src/ui/gui/rank.glade:519
 msgid "Rankit"
 msgstr ""
 
-#: src/ui/gui/rank.glade:534
+#: src/ui/gui/rank.glade:533
 msgid "Van der Wärden"
 msgstr ""
 
-#: src/ui/gui/rank.glade:551
+#: src/ui/gui/rank.glade:550
 msgid "Proportion Estimation Formula"
 msgstr ""
 
-#: src/ui/gui/rank.glade:614
+#: src/ui/gui/rank.glade:612
 msgid "_Mean"
 msgstr ""
 
-#: src/ui/gui/rank.glade:626
+#: src/ui/gui/rank.glade:624
 msgid "_Low"
 msgstr ""
 
-#: src/ui/gui/rank.glade:642
+#: src/ui/gui/rank.glade:640
 msgid "_High"
 msgstr ""
 
-#: src/ui/gui/rank.glade:660
+#: src/ui/gui/rank.glade:658
 msgid "_Sequential ranks to unique values"
 msgstr ""
 
-#: src/ui/gui/rank.glade:680
+#: src/ui/gui/rank.glade:678
 msgid "Rank Assigned to Ties"
 msgstr ""
 
-#: src/ui/gui/recode-dialog.c:879
+#: src/ui/gui/recode-dialog.c:878
 msgid "Recode into Different Variables"
 msgstr ""
 
-#: src/ui/gui/recode-dialog.c:882
+#: src/ui/gui/recode-dialog.c:881
 msgid "Recode into Same Variables"
 msgstr ""
 
-#: src/ui/gui/recode-dialog.c:913 src/ui/gui/recode-dialog.c:1015
+#: src/ui/gui/recode-dialog.c:912 src/ui/gui/recode-dialog.c:1014
 msgid "Old"
 msgstr ""
 
-#: src/ui/gui/recode-dialog.c:1274
+#: src/ui/gui/recode-dialog.c:1273
 msgid "Recode into Different Variables: Old and New Values "
 msgstr ""
 
-#: src/ui/gui/recode-dialog.c:1275
+#: src/ui/gui/recode-dialog.c:1274
 msgid "Recode into Same Variables: Old and New Values"
 msgstr ""
 
@@ -6329,17 +6320,17 @@ msgstr ""
 msgid "Residuals"
 msgstr ""
 
-#: src/ui/gui/select-cases-dialog.c:81
+#: src/ui/gui/select-cases-dialog.c:80
 #, c-format
 msgid "Approximately %3d%% of all cases."
 msgstr ""
 
-#: src/ui/gui/select-cases-dialog.c:82
+#: src/ui/gui/select-cases-dialog.c:81
 #, c-format
 msgid "Exactly %3d cases from the first %3d cases."
 msgstr ""
 
-#: src/ui/gui/select-cases-dialog.c:222
+#: src/ui/gui/select-cases-dialog.c:221
 #, c-format
 msgid "%d thru %d"
 msgstr ""
@@ -6646,44 +6637,44 @@ msgstr ""
 msgid "Confidence Interval: %2d %%"
 msgstr ""
 
-#: src/ui/gui/t-test-paired-samples.c:228
+#: src/ui/gui/t-test-paired-samples.c:227
 msgid "Var 1"
 msgstr ""
 
-#: src/ui/gui/t-test-paired-samples.c:229
+#: src/ui/gui/t-test-paired-samples.c:228
 msgid "Var 2"
 msgstr ""
 
-#: src/ui/gui/variable-info-dialog.c:89
+#: src/ui/gui/variable-info-dialog.c:88
 #, c-format
 msgid "Label: %s\n"
 msgstr ""
 
-#: src/ui/gui/variable-info-dialog.c:98
+#: src/ui/gui/variable-info-dialog.c:97
 #, c-format
 msgid "Type: %s\n"
 msgstr ""
 
-#: src/ui/gui/variable-info-dialog.c:102
+#: src/ui/gui/variable-info-dialog.c:101
 #, c-format
 msgid "Missing Values: %s\n"
 msgstr ""
 
-#: src/ui/gui/variable-info-dialog.c:107
+#: src/ui/gui/variable-info-dialog.c:106
 #, c-format
 msgid "Measurement Level: %s\n"
 msgstr ""
 
-#: src/ui/gui/variable-info-dialog.c:121
+#: src/ui/gui/variable-info-dialog.c:120
 msgid "Value Labels:\n"
 msgstr ""
 
-#: src/ui/gui/variable-info-dialog.c:133
+#: src/ui/gui/variable-info-dialog.c:132
 #, c-format
 msgid "%s %s\n"
 msgstr ""
 
-#: src/ui/gui/weight-cases-dialog.c:86
+#: src/ui/gui/weight-cases-dialog.c:85
 #, c-format
 msgid "Weight cases by %s"
 msgstr ""
index 8d309580acca22bcaa811acccf8fe85963369523..cff621f3456df7438562aa57d79dd78c4905fb3e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 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
@@ -38,7 +38,7 @@ struct case_map
                            corresponding source index. */
   };
 
-static void translate_case (struct ccase *, struct ccase *, void *map_);
+static struct ccase *translate_case (struct ccase *, void *map_);
 static bool destroy_case_map (void *map_);
 
 /* Creates and returns an empty map. */
@@ -83,20 +83,30 @@ case_map_destroy (struct case_map *map)
     }
 }
 
-/* Maps from SRC to DST, applying case map MAP. */
-void
-case_map_execute (const struct case_map *map,
-                  const struct ccase *src, struct ccase *dst)
-{
-  size_t dst_idx;
+/* If MAP is nonnull, returns a new case that is the result of
+   applying case map MAP to SRC, and unrefs SRC.
 
-  case_create (dst, map->value_cnt);
-  for (dst_idx = 0; dst_idx < map->value_cnt; dst_idx++)
+   If MAP is null, returns SRC unchanged. */
+struct ccase *
+case_map_execute (const struct case_map *map, struct ccase *src)
+{
+  if (map != NULL)
     {
-      int src_idx = map->map[dst_idx];
-      if (src_idx != -1)
-        *case_data_rw_idx (dst, dst_idx) = *case_data_idx (src, src_idx);
+      struct ccase *dst;
+      size_t dst_idx;
+
+      dst = case_create (map->value_cnt);
+      for (dst_idx = 0; dst_idx < map->value_cnt; dst_idx++)
+        {
+          int src_idx = map->map[dst_idx];
+          if (src_idx != -1)
+            *case_data_rw_idx (dst, dst_idx) = *case_data_idx (src, src_idx);
+        }
+      case_unref (src);
+      return dst;
     }
+  else
+    return src;
 }
 
 /* Returns the number of `union value's in cases created by
@@ -147,12 +157,11 @@ case_map_create_output_translator (struct case_map *map,
 }
 
 /* Casereader/casewriter translation callback. */
-static void
-translate_case (struct ccase *input, struct ccase *output, void *map_)
+static struct ccase *
+translate_case (struct ccase *input, void *map_)
 {
   struct case_map *map = map_;
-  case_map_execute (map, input, output);
-  case_destroy (input);
+  return case_map_execute (map, input);
 }
 
 /* Casereader/casewriter destruction callback. */
index 1c8608c291b7d09df64d692142f4c5915c6aa9a2..010dd487274d537af9035a53b5e5dac21ef12a91 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -34,8 +34,7 @@ struct dictionary;
 
 struct case_map *case_map_create (void);
 void case_map_destroy (struct case_map *);
-void case_map_execute (const struct case_map *,
-                       const struct ccase *, struct ccase *);
+struct ccase *case_map_execute (const struct case_map *, struct ccase *);
 
 size_t case_map_get_value_cnt (const struct case_map *);
 
index 9cfc0083c2b2b4ff624989cd2b42097ddd4b5f7e..a1251cb74cbfd816c7dab2ed54129659a0215e0b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 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
@@ -30,7 +30,7 @@
 struct case_matcher_input
   {
     struct subcase by_vars;
-    const struct ccase *data;
+    struct ccase **data;
     bool *is_minimal;
   };
 
@@ -55,13 +55,15 @@ case_matcher_create (void)
 
 /* Adds a new input file to case matcher CM.
    case_matcher_match() will compare the variables specified in
-   BY in case DATA and set *IS_MINIMAL appropriately.
+   BY in case *DATA and set *IS_MINIMAL appropriately.
+   (The caller may change the case that *DATA points to from one
+   call to the next.)
 
    All of the BY subcases provided to this function for a given
    CM must be conformable (see subcase_conformable()). */
 void
 case_matcher_add_input (struct case_matcher *cm, const struct subcase *by,
-                        const struct ccase *data, bool *is_minimal)
+                        struct ccase **data, bool *is_minimal)
 {
   struct case_matcher_input *input;
 
@@ -101,7 +103,7 @@ case_matcher_destroy (struct case_matcher *cm)
 static int
 compare_BY_3way (struct case_matcher_input *a, struct case_matcher_input *b)
 {
-  return subcase_compare_3way (&a->by_vars, a->data, &b->by_vars, b->data);
+  return subcase_compare_3way (&a->by_vars, *a->data, &b->by_vars, *b->data);
 }
 
 /* Compares the values of the BY variables in all of the nonnull
@@ -121,7 +123,7 @@ case_matcher_match (struct case_matcher *cm, union value **by)
 
   min = NULL;
   for (file = cm->inputs; file < &cm->inputs[cm->n_inputs]; file++)
-    if (!case_is_null (file->data))
+    if (*file->data != NULL)
       {
         int cmp = min != NULL ? compare_BY_3way (min, file) : 1;
         if (cmp < 0)
@@ -140,7 +142,7 @@ case_matcher_match (struct case_matcher *cm, union value **by)
     {
       for (file = cm->inputs; file < min; file++)
         *file->is_minimal = false;
-      subcase_extract (&min->by_vars, min->data, cm->by_values);
+      subcase_extract (&min->by_vars, *min->data, cm->by_values);
       *by = cm->by_values;
       return true;
     }
index d172f6113bcc6bcc84bd85b1a8e3158322b569f7..fa40781f0060d552b63840a24d304a9ab9ec3318 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 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
@@ -25,7 +25,7 @@ union value;
 
 struct case_matcher *case_matcher_create (void);
 void case_matcher_add_input (struct case_matcher *, const struct subcase *,
-                             const struct ccase *, bool *is_minimal);
+                             struct ccase **, bool *is_minimal);
 void case_matcher_destroy (struct case_matcher *);
 
 bool case_matcher_match (struct case_matcher *, union value **by);
index e6fc3de46c834e6acc48566d8c35847150244be3..ca3a6a564421552f4241900caa2fb21708f08226 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -198,25 +198,23 @@ case_tmpfile_get_values (const struct case_tmpfile *ctf,
           && do_read (ctf, sizeof *values * value_cnt, values));
 }
 
-/* Reads the case numbered CASE_IDX from CTF into C.
-   Returns true if successful, false if CTF is tainted or an I/O
-   error occurs during the operation.
+/* Reads the case numbered CASE_IDX from CTF.
+   Returns the case if successful or a null pointer if CTF is
+   tainted or an I/O error occurs during the operation.
 
    The results of this function are undefined if the case read
    from CTF had not previously been written. */
-bool
-case_tmpfile_get_case (const struct case_tmpfile *ctf, casenumber case_idx,
-                       struct ccase *c)
+struct ccase *
+case_tmpfile_get_case (const struct case_tmpfile *ctf, casenumber case_idx)
 {
-  case_create (c, ctf->value_cnt);
+  struct ccase *c = case_create (ctf->value_cnt);
   if (case_tmpfile_get_values (ctf, case_idx, 0,
                                case_data_all_rw (c), ctf->value_cnt))
-    return true;
+    return c;
   else
     {
-      case_destroy (c);
-      case_nullify (c);
-      return false;
+      case_unref (c);
+      return NULL;
     }
 }
 
@@ -246,7 +244,7 @@ case_tmpfile_put_case (struct case_tmpfile *ctf, casenumber case_idx,
 {
   bool ok = case_tmpfile_put_values (ctf, case_idx, 0,
                                      case_data_all (c), ctf->value_cnt);
-  case_destroy (c);
+  case_unref (c);
   return ok;
 }
 
index 3a92debc6e8e1b40be4e98342b96cd50a3487629..a5916249d45fcf04ca55d2845da70ff8ebe618f2 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -38,11 +38,10 @@ bool case_tmpfile_error (const struct case_tmpfile *);
 void case_tmpfile_force_error (struct case_tmpfile *);
 const struct taint *case_tmpfile_get_taint (const struct case_tmpfile *);
 
-bool case_tmpfile_get_values (const struct case_tmpfile *,
+ bool case_tmpfile_get_values (const struct case_tmpfile *,
                               casenumber, size_t start_value,
                               union value[], size_t value_cnt);
-bool case_tmpfile_get_case (const struct case_tmpfile *,
-                            casenumber, struct ccase *);
+struct ccase *case_tmpfile_get_case (const struct case_tmpfile *, casenumber);
 
 bool case_tmpfile_put_values (struct case_tmpfile *,
                               casenumber, size_t start_value,
index cec6f21e1be8ae94ccd7dcbc2284841e91ec9cab..4432579e5d2e1284102a9ab7854d79db3b10d197 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2007, 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
@@ -20,6 +20,7 @@
 
 #include <assert.h>
 #include <limits.h>
+#include <stddef.h>
 #include <stdlib.h>
 
 #include <data/value.h>
 #include "minmax.h"
 #include "xalloc.h"
 
-/* Reference-counted case implementation. */
-struct case_data
-  {
-    size_t value_cnt;                   /* Number of values. */
-    unsigned ref_cnt;                   /* Reference count. */
-    union value values[1];              /* Values. */
-  };
-
-/* Ensures that C does not share data with any other case. */
-static void
-case_unshare (struct ccase *c)
-{
-  if (c->case_data->ref_cnt > 1)
-    {
-      struct case_data *cd = c->case_data;
-      cd->ref_cnt--;
-      case_create (c, cd->value_cnt);
-      memcpy (c->case_data->values, cd->values,
-              sizeof *cd->values * cd->value_cnt);
-    }
-}
-
-/* Returns the number of bytes needed by a case with VALUE_CNT
+/* Returns the number of bytes needed by a case with N_VALUES
    values. */
 static size_t
-case_size (size_t value_cnt)
+case_size (size_t n_values)
 {
-  return (offsetof (struct case_data, values)
-          + value_cnt * sizeof (union value));
+  return offsetof (struct ccase, values) + n_values * sizeof (union value);
 }
 
-/* Initializes C as a null case. */
-void
-case_nullify (struct ccase *c)
+/* Returns true if case C contains COUNT cases starting at index
+   OFS, false if any of those values are out of range for case
+   C. */
+static inline bool UNUSED
+range_is_valid (const struct ccase *c, size_t ofs, size_t count)
 {
-  c->case_data = NULL;
+  return (count <= c->n_values
+          && ofs <= c->n_values
+          && ofs + count <= c->n_values);
 }
 
-/* Returns true iff C is a null case. */
-bool
-case_is_null (const struct ccase *c)
-{
-  return c->case_data == NULL;
-}
-
-/* Initializes C as a new case that can store VALUE_CNT values.
+/* Creates and returns a new case that can store N_VALUES values.
    The values have indeterminate contents until explicitly
    written. */
-void
-case_create (struct ccase *c, size_t value_cnt)
+struct ccase *
+case_create (size_t n_values)
 {
-  if (!case_try_create (c, value_cnt))
+  struct ccase *c = case_try_create (n_values);
+  if (c == NULL)
     xalloc_die ();
+  return c;
 }
 
-/* Initializes CLONE as a copy of ORIG. */
-void
-case_clone (struct ccase *clone, const struct ccase *orig)
+/* Like case_create, but returns a null pointer if not enough
+   memory is available. */
+struct ccase *
+case_try_create (size_t n_values)
 {
-  assert (orig->case_data->ref_cnt > 0);
-
-  if (clone != orig)
-    *clone = *orig;
-  orig->case_data->ref_cnt++;
-#ifdef DEBUGGING
-  case_unshare (clone);
-#endif
-}
-
-/* Replaces DST by SRC and nullifies SRC.
-   DST and SRC must be initialized cases at entry. */
-void
-case_move (struct ccase *dst, struct ccase *src)
-{
-  assert (src->case_data->ref_cnt > 0);
-
-  if (dst != src)
+  struct ccase *c = malloc (case_size (n_values));
+  if (c)
     {
-      *dst = *src;
-      case_nullify (src);
+      c->n_values = n_values;
+      c->ref_cnt = 1;
     }
+  return c;
 }
 
-/* Destroys case C. */
-void
-case_destroy (struct ccase *c)
+/* Resizes case C, which must not be shared, to N_VALUES union
+   values.  If N_VALUES is greater than the current size of case
+   C, then the newly added values have indeterminate content that
+   the caller is responsible for initializing.  Returns the new
+   case. */
+struct ccase *
+case_resize (struct ccase *c, size_t n_values)
 {
-  struct case_data *cd;
-
-  cd = c->case_data;
-  if (cd != NULL && --cd->ref_cnt == 0)
+  assert (!case_is_shared (c));
+  if (n_values != c->n_values)
     {
-      memset (cd->values, 0xcc, sizeof *cd->values * cd->value_cnt);
-      cd->value_cnt = 0xdeadbeef;
-      free (cd);
+      c->n_values = n_values;
+      return xrealloc (c, case_size (n_values));
     }
+  else
+    return c;
 }
 
-/* Returns the number of union values in C. */
-size_t
-case_get_value_cnt (const struct ccase *c)
-{
-  return c->case_data->value_cnt;
-}
+/* case_unshare_and_resize(C, N) is equivalent to
+   case_resize(case_unshare(C), N), but it is faster if case C is
+   shared.
 
-/* Resizes case C to NEW_CNT union values. */
-void
-case_resize (struct ccase *c, size_t new_cnt)
+   Returns the new case.*/
+struct ccase *
+case_unshare_and_resize (struct ccase *c, size_t n_values)
 {
-  size_t old_cnt = case_get_value_cnt (c);
-  if (old_cnt != new_cnt)
+  if (!case_is_shared (c))
+    return case_resize (c, n_values);
+  else
     {
-      struct ccase new;
-
-      case_create (&new, new_cnt);
-      case_copy (&new, 0, c, 0, MIN (old_cnt, new_cnt));
-      case_swap (&new, c);
-      case_destroy (&new);
+      struct ccase *new = case_create (n_values);
+      case_copy (new, 0, c, 0, MIN (n_values, c->n_values));
+      c->ref_cnt--;
+      return new;
     }
 }
 
-/* Swaps cases A and B. */
-void
-case_swap (struct ccase *a, struct ccase *b)
-{
-  struct case_data *t = a->case_data;
-  a->case_data = b->case_data;
-  b->case_data = t;
-}
+/* Copies N_VALUES values from SRC (starting at SRC_IDX) to DST
+   (starting at DST_IDX).
 
-/* Attempts to create C as a new case that holds VALUE_CNT
-   values.  Returns true if successful, false if memory
-   allocation failed. */
-bool
-case_try_create (struct ccase *c, size_t value_cnt)
-{
-  c->case_data = malloc (case_size (value_cnt));
-  if (c->case_data != NULL)
-    {
-      c->case_data->value_cnt = value_cnt;
-      c->case_data->ref_cnt = 1;
-      return true;
-    }
-
-  return false;
-}
-
-/* Tries to initialize CLONE as a copy of ORIG.
-   Returns true if successful, false if memory allocation
-   failed. */
-bool
-case_try_clone (struct ccase *clone, const struct ccase *orig)
-{
-  case_clone (clone, orig);
-  return true;
-}
-
-/* Copies VALUE_CNT values from SRC (starting at SRC_IDX) to DST
-   (starting at DST_IDX). */
+   DST must not be shared. */
 void
 case_copy (struct ccase *dst, size_t dst_idx,
            const struct ccase *src, size_t src_idx,
-           size_t value_cnt)
+           size_t n_values)
 {
-  assert (dst->case_data->ref_cnt > 0);
-  assert (dst_idx + value_cnt <= dst->case_data->value_cnt);
+  assert (!case_is_shared (dst));
+  assert (range_is_valid (dst, dst_idx, n_values));
+  assert (range_is_valid (src, src_idx, n_values));
 
-  assert (src->case_data->ref_cnt > 0);
-  assert (src_idx + value_cnt <= src->case_data->value_cnt);
-
-  if (dst->case_data != src->case_data || dst_idx != src_idx)
-    {
-      case_unshare (dst);
-      memmove (dst->case_data->values + dst_idx,
-               src->case_data->values + src_idx,
-               sizeof *dst->case_data->values * value_cnt);
-    }
+  if (dst != src || dst_idx != src_idx)
+    memmove (dst->values + dst_idx, src->values + src_idx,
+             sizeof *dst->values * n_values);
 }
 
-/* Copies VALUE_CNT values out of case C to VALUES, starting at
+/* Copies N_VALUES values out of case C to VALUES, starting at
    the given START_IDX. */
 void
 case_copy_out (const struct ccase *c,
-               size_t start_idx, union value *values, size_t value_cnt)
+               size_t start_idx, union value *values, size_t n_values)
 {
-  assert (c->case_data->ref_cnt > 0);
-  assert (value_cnt <= c->case_data->value_cnt);
-  assert (start_idx + value_cnt <= c->case_data->value_cnt);
-
-  memcpy (values, c->case_data->values + start_idx,
-          value_cnt * sizeof *values);
+  assert (range_is_valid (c, start_idx, n_values));
+  memcpy (values, c->values + start_idx, n_values * sizeof *values);
 }
 
-/* Copies VALUE_CNT values from VALUES into case C, staring at
-   the given START_IDX. */
+/* Copies N_VALUES values from VALUES into case C, starting at
+   the given START_IDX.
+
+   C must not be shared. */
 void
 case_copy_in (struct ccase *c,
-              size_t start_idx, const union value *values, size_t value_cnt)
+              size_t start_idx, const union value *values, size_t n_values)
 {
-  assert (c->case_data->ref_cnt > 0);
-  assert (value_cnt <= c->case_data->value_cnt);
-  assert (start_idx + value_cnt <= c->case_data->value_cnt);
-
-  case_unshare (c);
-  memcpy (c->case_data->values + start_idx, values,
-          value_cnt * sizeof *values);
+  assert (!case_is_shared (c));
+  assert (range_is_valid (c, start_idx, n_values));
+  memcpy (c->values + start_idx, values, n_values * sizeof *values);
 }
 
 /* Returns a pointer to the `union value' used for the
@@ -247,30 +163,21 @@ case_data (const struct ccase *c, const struct variable *v)
   return case_data_idx (c, var_get_case_index (v));
 }
 
-/* Returns the numeric value of the `union value' in C for
-   variable V.
-   Case C must be drawn from V's dictionary. */
-double
-case_num (const struct ccase *c, const struct variable *v)
+/* Returns a pointer to the `union value' used for the element of
+   C numbered IDX.  The caller must not modify the returned
+   data. */
+const union value *
+case_data_idx (const struct ccase *c, size_t idx)
 {
-  return case_num_idx (c, var_get_case_index (v));
+  assert (idx < c->n_values);
+  return &c->values[idx];
 }
 
-/* Returns the string value of the `union value' in C for
-   variable V.
-   Case C must be drawn from V's dictionary.
-   (Note that the value is not null-terminated.)
-   The caller must not modify the return value. */
-const char *
-case_str (const struct ccase *c, const struct variable *v)
-{
-  return case_str_idx (c, var_get_case_index (v));
-}
+/* Returns a pointer to the `union value' used for the element of
+   C for variable V.  Case C must be drawn from V's dictionary.
+   The caller is allowed to modify the returned data.
 
-/* Returns a pointer to the `union value' used for the
-   element of C for variable V.
-   Case C must be drawn from V's dictionary.
-   The caller is allowed to modify the returned data. */
+   Case C must not be shared. */
 union value *
 case_data_rw (struct ccase *c, const struct variable *v)
 {
@@ -279,14 +186,24 @@ case_data_rw (struct ccase *c, const struct variable *v)
 
 /* Returns a pointer to the `union value' used for the
    element of C numbered IDX.
-   The caller must not modify the returned data. */
-const union value *
-case_data_idx (const struct ccase *c, size_t idx)
+   The caller is allowed to modify the returned data.
+
+   Case C must not be shared. */
+union value *
+case_data_rw_idx (struct ccase *c, size_t idx)
 {
-  assert (c->case_data->ref_cnt > 0);
-  assert (idx < c->case_data->value_cnt);
+  assert (!case_is_shared (c));
+  assert (idx < c->n_values);
+  return &c->values[idx];
+}
 
-  return &c->case_data->values[idx];
+/* Returns the numeric value of the `union value' in C for
+   variable V.
+   Case C must be drawn from V's dictionary. */
+double
+case_num (const struct ccase *c, const struct variable *v)
+{
+  return case_num_idx (c, var_get_case_index (v));
 }
 
 /* Returns the numeric value of the `union value' in C numbered
@@ -294,57 +211,53 @@ case_data_idx (const struct ccase *c, size_t idx)
 double
 case_num_idx (const struct ccase *c, size_t idx)
 {
-  assert (c->case_data->ref_cnt > 0);
-  assert (idx < c->case_data->value_cnt);
-
-  return c->case_data->values[idx].f;
+  assert (idx < c->n_values);
+  return c->values[idx].f;
 }
 
-/* Returns the string value of the `union value' in C numbered
-   IDX.
-   (Note that the value is not null-terminated.)
-   The caller must not modify the return value. */
+/* Returns the string value of the `union value' in C for
+   variable V.  Case C must be drawn from V's dictionary.  The
+   caller must not modify the return value.
+
+   Like all "union value"s, the return value is not
+   null-terminated. */
 const char *
-case_str_idx (const struct ccase *c, size_t idx)
+case_str (const struct ccase *c, const struct variable *v)
 {
-  assert (c->case_data->ref_cnt > 0);
-  assert (idx < c->case_data->value_cnt);
-
-  return c->case_data->values[idx].s;
+  return case_str_idx (c, var_get_case_index (v));
 }
 
-/* Returns a pointer to the `union value' used for the
-   element of C numbered IDX.
-   The caller is allowed to modify the returned data. */
-union value *
-case_data_rw_idx (struct ccase *c, size_t idx)
-{
-  assert (c->case_data->ref_cnt > 0);
-  assert (idx < c->case_data->value_cnt);
+/* Returns the string value of the `union value' in C numbered
+   IDX.  The caller must not modify the return value.
 
-  case_unshare (c);
-  return &c->case_data->values[idx];
+   Like all "union value"s, the return value is not
+   null-terminated. */
+const char *
+case_str_idx (const struct ccase *c, size_t idx)
+{
+  assert (idx < c->n_values);
+  return c->values[idx].s;
 }
 
-/* Compares the values of the VAR_CNT variables in VP
+/* Compares the values of the N_VARS variables in VP
    in cases A and B and returns a strcmp()-type result. */
 int
 case_compare (const struct ccase *a, const struct ccase *b,
-              const struct variable *const *vp, size_t var_cnt)
+              const struct variable *const *vp, size_t n_vars)
 {
-  return case_compare_2dict (a, b, vp, vp, var_cnt);
+  return case_compare_2dict (a, b, vp, vp, n_vars);
 }
 
-/* Compares the values of the VAR_CNT variables in VAP in case CA
-   to the values of the VAR_CNT variables in VBP in CB
+/* Compares the values of the N_VARS variables in VAP in case CA
+   to the values of the N_VARS variables in VBP in CB
    and returns a strcmp()-type result. */
 int
 case_compare_2dict (const struct ccase *ca, const struct ccase *cb,
                     const struct variable *const *vap,
-               const struct variable *const *vbp,
-                    size_t var_cnt)
+                    const struct variable *const *vbp,
+                    size_t n_vars)
 {
-  for (; var_cnt-- > 0; vap++, vbp++)
+  for (; n_vars-- > 0; vap++, vbp++)
     {
       const struct variable *va = *vap;
       const struct variable *vb = *vbp;
@@ -375,26 +288,34 @@ case_compare_2dict (const struct ccase *ca, const struct ccase *cb,
 /* Returns a pointer to the array of `union value's used for C.
    The caller must *not* modify the returned data.
 
-   NOTE: This function breaks the case abstraction.  It should
-   *not* be used often.  Prefer the other case functions. */
+   This function breaks the case abstraction.  It should *not* be
+   commonly used.  Prefer the other case functions. */
 const union value *
 case_data_all (const struct ccase *c)
 {
-  assert (c->case_data->ref_cnt > 0);
-
-  return c->case_data->values;
+  return c->values;
 }
 
 /* Returns a pointer to the array of `union value's used for C.
    The caller is allowed to modify the returned data.
 
-   NOTE: This function breaks the case abstraction.  It should
-   *not* be used often.  Prefer the other case functions. */
+   Case C must not be shared.
+
+   This function breaks the case abstraction.  It should *not* be
+   commonly used.  Prefer the other case functions. */
 union value *
 case_data_all_rw (struct ccase *c)
 {
-  assert (c->case_data->ref_cnt > 0);
+  assert (!case_is_shared (c));
+  return c->values;
+}
 
-  case_unshare (c);
-  return c->case_data->values;
+/* Internal helper function for case_unshare. */
+struct ccase *
+case_unshare__ (struct ccase *old)
+{
+  struct ccase *new = case_create (old->n_values);
+  memcpy (new->values, old->values, old->n_values * sizeof old->values[0]);
+  --old->ref_cnt;
+  return new;
 }
index aa5b9dd0d7c99397ebcb00c7ef908f6ee6a4d719..6f53772688c3c1f29ba15cc0475735d0803762e4 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2007, 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
@@ -20,6 +20,8 @@
 #include <limits.h>
 #include <stddef.h>
 #include <stdbool.h>
+#include <stdlib.h>
+#include <libpspp/compiler.h>
 #include "value.h"
 
 struct variable;
@@ -29,57 +31,130 @@ struct variable;
 #define CASENUMBER_MAX LONG_MAX
 typedef long int casenumber;
 
-/* Opaque structure that represents a case.  Use accessor
-   functions instead of accessing any members directly.  Use
-   case_move() or case_clone() instead of copying.  */
+/* Reference-counted case implementation.
+
+   A newly created case has a single owner (the code that created
+   it), represented by an initial reference count of 1.  Other
+   code that receives the case may keep a virtual copy of it by
+   calling case_ref, which increments the case's reference count.
+   When this is done, the case becomes shared between its
+   original owner and each piece of code that incremented the
+   reference count.
+
+   A shared case (one whose reference count is greater than 1)
+   must not be modified, because this would make the case change
+   in the view of every reference count holder, not just the one
+   that intended to change the case.  Because the purpose of
+   keeping the reference count is to make a virtual copy of the
+   case, this is undesirable behavior.  The case_unshare function
+   provides a solution, by making a new, unshared copy of a
+   shared case. */
 struct ccase
   {
-    struct case_data *case_data;        /* Actual data. */
+    size_t n_values;            /* Number of values. */
+    size_t ref_cnt;             /* Reference count. */
+    union value values[1];      /* Values. */
   };
 
-void case_nullify (struct ccase *);
-bool case_is_null (const struct ccase *);
+struct ccase *case_create (size_t n_values) MALLOC_LIKE;
+struct ccase *case_try_create (size_t n_values) MALLOC_LIKE;
 
-void case_create (struct ccase *, size_t value_cnt);
-void case_clone (struct ccase *, const struct ccase *);
-void case_move (struct ccase *, struct ccase *);
-void case_destroy (struct ccase *);
+static inline struct ccase *case_unshare (struct ccase *) WARN_UNUSED_RESULT;
+static inline struct ccase *case_ref (const struct ccase *);
+static inline void case_unref (struct ccase *);
+static inline bool case_is_shared (const struct ccase *);
 
-size_t case_get_value_cnt (const struct ccase *);
+static inline size_t case_get_value_cnt (const struct ccase *);
 
-void case_resize (struct ccase *, size_t new_cnt);
-void case_swap (struct ccase *, struct ccase *);
-
-bool case_try_create (struct ccase *, size_t value_cnt);
-bool case_try_clone (struct ccase *, const struct ccase *);
+struct ccase *case_resize (struct ccase *, size_t new_cnt) WARN_UNUSED_RESULT;
+struct ccase *case_unshare_and_resize (struct ccase *, size_t new_cnt)
+  WARN_UNUSED_RESULT;
 
 void case_copy (struct ccase *dst, size_t dst_idx,
                 const struct ccase *src, size_t src_idx,
                 size_t cnt);
 
 void case_copy_out (const struct ccase *,
-                       size_t start_idx, union value *, size_t value_cnt);
+                    size_t start_idx, union value *, size_t n_values);
 void case_copy_in (struct ccase *,
-                       size_t start_idx, const union value *, size_t value_cnt);
+                   size_t start_idx, const union value *, size_t n_values);
 
 const union value *case_data (const struct ccase *, const struct variable *);
-double case_num (const struct ccase *, const struct variable *);
-const char *case_str (const struct ccase *, const struct variable *);
+const union value *case_data_idx (const struct ccase *, size_t idx);
 union value *case_data_rw (struct ccase *, const struct variable *);
+union value *case_data_rw_idx (struct ccase *, size_t idx);
 
-const union value *case_data_idx (const struct ccase *, size_t idx);
+double case_num (const struct ccase *, const struct variable *);
 double case_num_idx (const struct ccase *, size_t idx);
+
+const char *case_str (const struct ccase *, const struct variable *);
 const char *case_str_idx (const struct ccase *, size_t idx);
-union value *case_data_rw_idx (struct ccase *, size_t idx);
 
 int case_compare (const struct ccase *, const struct ccase *,
-                  const struct variable *const *, size_t var_cnt);
+                  const struct variable *const *, size_t n_vars);
 int case_compare_2dict (const struct ccase *, const struct ccase *,
                         const struct variable *const *,
                        const struct variable *const *,
-                        size_t var_cnt);
+                        size_t n_vars);
 
 const union value *case_data_all (const struct ccase *);
 union value *case_data_all_rw (struct ccase *);
+\f
+struct ccase *case_unshare__ (struct ccase *);
+
+/* If C is a shared case, that is, if it has a reference count
+   greater than 1, makes a new unshared copy and returns it,
+   decrementing C's reference count.  If C is not shared (its
+   reference count is 1), returns C.
+
+   This function should be used before attempting to modify any
+   of the data in a case that might be shared, e.g.:
+        c = case_unshare (c);              // Make sure that C is not shared.
+        case_data_rw (c, myvar)->f = 1;    // Modify data in C.
+*/
+static inline struct ccase *
+case_unshare (struct ccase *c)
+{
+  if (case_is_shared (c))
+    c = case_unshare__ (c);
+  return c;
+}
+
+/* Increments case C's reference count and returns C.  Afterward,
+   case C is shared among its reference count holders. */
+static inline struct ccase *
+case_ref (const struct ccase *c_)
+{
+  struct ccase *c = (struct ccase *) c_;
+  c->ref_cnt++;
+  return c;
+}
+
+/* Decrements case C's reference count.  Frees C if its
+   reference count drops to 0.
+
+   If C is a null pointer, this function has no effect. */
+static inline void
+case_unref (struct ccase *c)
+{
+  if (c != NULL && !--c->ref_cnt)
+    free (c);
+}
+
+/* Returns true if case C is shared.  A case that is shared
+   cannot be modified directly.  Instead, an unshared copy must
+   first be made with case_unshare(). */
+static inline bool
+case_is_shared (const struct ccase *c)
+{
+  return c->ref_cnt > 1;
+}
+
+/* Returns the number of union values in C. */
+static inline size_t
+case_get_value_cnt (const struct ccase *c)
+{
+  return c->n_values;
+}
 
 #endif /* data/case.h */
index 75925650f277ad8fbdf0f83b548eebb217b9138f..86788ba7a3bc5afcbd280ad2be920685a48e76db 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -80,28 +80,26 @@ casegrouper_get_next_group (struct casegrouper *grouper,
   if (grouper->same_group != NULL)
     {
       struct casewriter *writer;
-      struct ccase group_case, tmp;
+      struct ccase *group_case, *tmp;
 
-      if (!casereader_read (grouper->reader, &group_case))
+      group_case = casereader_read (grouper->reader);
+      if (group_case == NULL)
         {
           *reader = NULL;
           return false;
         }
 
       writer = autopaging_writer_create (casereader_get_value_cnt (grouper->reader));
-      case_clone (&tmp, &group_case);
-      casewriter_write (writer, &tmp);
+      case_ref (group_case);
+      casewriter_write (writer, group_case);
 
-      while (casereader_peek (grouper->reader, 0, &tmp)
-             && grouper->same_group (&group_case, &tmp, grouper->aux))
+      while ((tmp = casereader_peek (grouper->reader, 0)) != NULL
+             && grouper->same_group (group_case, tmp, grouper->aux))
         {
-          struct ccase discard;
-          casereader_read (grouper->reader, &discard);
-          case_destroy (&discard);
-          casewriter_write (writer, &tmp);
+          case_unref (casereader_read (grouper->reader));
+          casewriter_write (writer, tmp);
         }
-      case_destroy (&tmp);
-      case_destroy (&group_case);
+      case_unref (group_case);
 
       *reader = casewriter_make_reader (writer);
       return true;
index f789244dd53b13d4b41a3498c89112bb5ea2cdf7..4f7ece7e03bac3dc6950a2d977a0203ddad62c23 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -247,7 +247,8 @@ caseinit_mark_for_init (struct caseinit *ci, const struct dictionary *d)
   init_list_mark (&ci->left_values, &ci->preinited_values, LEAVE_LEFT, d);
 }
 
-/* Initializes variables in C as described by CI. */
+/* Initializes variables in *C as described by CI.
+   C must not be shared. */
 void
 caseinit_init_vars (const struct caseinit *ci, struct ccase *c)
 {
index fcd264e9dc35e08f8d7737b83973ca9c5d4f9e40..d387f5ea03181794e790ea297a3b10cdc8337880 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -86,22 +86,22 @@ casereader_create_filter_func (struct casereader *subreader,
 }
 
 /* Internal read function for filtering casereader. */
-static bool
-casereader_filter_read (struct casereader *reader UNUSED, void *filter_,
-                        struct ccase *c)
+static struct ccase *
+casereader_filter_read (struct casereader *reader UNUSED, void *filter_)
 
 {
   struct casereader_filter *filter = filter_;
   for (;;)
     {
-      if (!casereader_read (filter->subreader, c))
-        return false;
+      struct ccase *c = casereader_read (filter->subreader);
+      if (c == NULL)
+        return NULL;
       else if (filter->include (c, filter->aux))
-        return true;
+        return c;
       else if (filter->exclude != NULL)
         casewriter_write (filter->exclude, c);
       else
-        case_destroy (c);
+        case_unref (c);
     }
 }
 
@@ -115,12 +115,12 @@ casereader_filter_destroy (struct casereader *reader, void *filter_)
      casewriter, if there is one. */
   if (filter->exclude != NULL)
     {
-      struct ccase c;
-      while (casereader_read (filter->subreader, &c))
-        if (filter->include (&c, filter->aux))
-          case_destroy (&c);
+      struct ccase *c;
+      while ((c = casereader_read (filter->subreader)) != NULL)
+        if (filter->include (c, filter->aux))
+          case_unref (c);
         else
-          casewriter_write (filter->exclude, &c);
+          casewriter_write (filter->exclude, c);
     }
 
   casereader_destroy (filter->subreader);
index 772209810a85e44c2f7474a44fcb25235735cf98..31d8a6d4c88e67a6afab5ad2e372c0b5041f6790 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -43,20 +43,23 @@ struct casereader_class
   {
     /* Mandatory.
 
-       Reads the next case from READER into case C, which the
-       casereader must create and which the client is responsible
-       for destroying.  If successful, returns true and advances
-       READER to the next case, so that the next call to this
-       function will read the next case.  The case just read will
-       never be read again by a call to this function for READER.
+       Reads the next case from READER.  If successful, returns
+       the case and advances READER, so that the next call to
+       this function will read the following case.  The case just
+       read will never be read again by a call to this function
+       for READER.
 
-       At end of file or upon an I/O error, returns false.  After
-       false is returned once, this function will not be called
-       again for the given READER.
+       If a case is successfully returned, the client is
+       responsible for calling case_unref upon it when it is no
+       longer needed.
+
+       At end of file or upon an I/O error, returns a null
+       pointer.  After null is returned once, this function will
+       not be called again for the given READER.
 
        If an I/O error occurs, this function should call
        casereader_force_error on READER. */
-    bool (*read) (struct casereader *reader, void *aux, struct ccase *c);
+    struct ccase *(*read) (struct casereader *reader, void *aux);
 
     /* Mandatory.
 
@@ -88,22 +91,23 @@ struct casereader_class
        (But it might be easier to use the random-access
        casereader wrapper instead.)
 
-       Reads the case at 0-based offset IDX from the beginning of
-       READER into case C, which the casereader must create and
-       which the client is responsible for destroying.
+       Reads and returns the case at 0-based offset IDX from the
+       beginning of READER.  If a case is successfully returned,
+       the client is responsible for calling case_unref upon it
+       when it is no longer needed.
 
-       At end of file or upon an I/O error, returns false.  If
-       this function returns false, then it will never be called
-       again for an equal or greater value of IDX, and the "read"
-       member function will never be called to advance as far as
-       IDX cases further into the casereader.  That is, returning
-       false indicates that the casereader has fewer than IDX
-       cases left.
+       At end of file or upon an I/O error, returns a null
+       pointer.  If this function returns null, then it will
+       never be called again for an equal or greater value of
+       IDX, and the "read" member function will never be called
+       to advance as far as IDX cases further into the
+       casereader.  That is, returning null indicates that the
+       casereader has fewer than IDX cases left.
 
        If an I/O error occurs, this function should call
        casereader_force_error on READER. */
-    bool (*peek) (struct casereader *reader, void *aux, casenumber idx,
-                  struct ccase *c);
+    struct ccase *(*peek) (struct casereader *reader, void *aux,
+                           casenumber idx);
   };
 
 struct casereader *
@@ -119,21 +123,22 @@ struct casereader_random_class
     /* Mandatory.
 
        Reads the case at 0-based offset IDX from the beginning of
-       READER into case C, which the casereader must create and
-       which the client is responsible for destroying.
-
-       At end of file or upon an I/O error, returns false.  If
-       this function returns false, then it will never be called
-       again for an equal or greater value of IDX, and the "read"
-       member function will never be called to advance as far as
-       IDX cases further into the casereader.  That is, returning
-       false indicates that the casereader has fewer than IDX
-       cases.
+       READER.  If a case is successfully returned, the client is
+       responsible for calling case_unref upon it when it is no
+       longer needed.
+
+       At end of file or upon an I/O error, returns a null
+       pointer.  If this function returns null, then it will
+       never be called again for an equal or greater value of
+       IDX, and the "read" member function will never be called
+       to advance as far as IDX cases further into the
+       casereader.  That is, returning null indicates that the
+       casereader has fewer than IDX cases.
 
        If an I/O error occurs, this function should call
        casereader_force_error on READER. */
-    bool (*read) (struct casereader *reader, void *aux, casenumber idx,
-                  struct ccase *c);
+    struct ccase *(*read) (struct casereader *reader, void *aux,
+                           casenumber idx);
 
     /* Mandatory.
 
index ae22f1297e19dbe5a12e6d9e2ec49f75ce8de087..d55e18e50292282a6e7c6d95233802fb42c920ed 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -32,7 +32,7 @@ struct casereader_translator
   {
     struct casereader *subreader; /* Source of input cases. */
 
-    void (*translate) (struct ccase *input, struct ccase *output, void *aux);
+    struct ccase *(*translate) (struct ccase *input, void *aux);
     bool (*destroy) (void *aux);
     void *aux;
   };
@@ -41,9 +41,9 @@ static const struct casereader_class casereader_translator_class;
 
 /* Creates and returns a new casereader whose cases are produced
    by reading from SUBREADER and passing through TRANSLATE, which
-   must create case OUTPUT, with OUTPUT_VALUE_CNT values, and
-   populate it based on INPUT and auxiliary data AUX.  TRANSLATE
-   must also destroy INPUT.
+   must return the translated case, with OUTPUT_VALUE_CNT values,
+   and populate it based on INPUT and auxiliary data AUX.
+   TRANSLATE must destroy its input case.
 
    When the translating casereader is destroyed, DESTROY will be
    called to allow any state maintained by TRANSLATE to be freed.
@@ -54,9 +54,8 @@ static const struct casereader_class casereader_translator_class;
 struct casereader *
 casereader_create_translator (struct casereader *subreader,
                               size_t output_value_cnt,
-                              void (*translate) (struct ccase *input,
-                                                 struct ccase *output,
-                                                 void *aux),
+                              struct ccase *(*translate) (struct ccase *input,
+                                                          void *aux),
                               bool (*destroy) (void *aux),
                               void *aux)
 {
@@ -75,20 +74,15 @@ casereader_create_translator (struct casereader *subreader,
 }
 
 /* Internal read function for translating casereader. */
-static bool
+static struct ccase *
 casereader_translator_read (struct casereader *reader UNUSED,
-                            void *ct_, struct ccase *c)
+                            void *ct_)
 {
   struct casereader_translator *ct = ct_;
-  struct ccase tmp;
-
-  if (casereader_read (ct->subreader, &tmp))
-    {
-      ct->translate (&tmp, c, ct->aux);
-      return true;
-    }
-  else
-    return false;
+  struct ccase *tmp = casereader_read (ct->subreader);
+  if (tmp)
+    tmp = ct->translate (tmp, ct->aux);
+  return tmp;
 }
 
 /* Internal destroy function for translating casereader. */
@@ -123,8 +117,7 @@ struct casereader_append_numeric
 
 static bool can_destroy (void *can_);
 
-static void can_translate (struct ccase *input, struct ccase *output,
-                          void *can_);
+static struct ccase *can_translate (struct ccase *, void *can_);
 
 /* Creates and returns a new casereader whose cases are produced
    by reading from SUBREADER and appending an additional value,
@@ -152,15 +145,14 @@ casereader_create_append_numeric (struct casereader *subreader,
 }
 
 
-static void
-can_translate (struct ccase *input, struct ccase *output, void *can_)
+static struct ccase *
+can_translate (struct ccase *c, void *can_)
 {
   struct casereader_append_numeric *can = can_;
-  double new_value = can->func (input, can->n++, can->aux);
-  case_nullify (output);
-  case_move (output, input);
-  case_resize (output, can->value_ofs + 1);
-  case_data_rw_idx (output, can->value_ofs)->f = new_value;
+  double new_value = can->func (c, can->n++, can->aux);
+  c = case_unshare_and_resize (c, can->value_ofs + 1);
+  case_data_rw_idx (c, can->value_ofs)->f = new_value;
+  return c;
 }
 
 static bool
@@ -231,8 +223,7 @@ struct casereader_append_rank
 
 static bool car_destroy (void *car_);
 
-static void car_translate (struct ccase *input, struct ccase *output,
-                          void *car_);
+static struct ccase *car_translate (struct ccase *input, void *car_);
 
 /* Creates and returns a new casereader whose cases are produced
    by reading from SUBREADER and appending an additional value,
@@ -293,9 +284,8 @@ car_destroy (void *car_)
   return true;
 }
 
-
-static void
-car_translate (struct ccase *input, struct ccase *output,  void *car_)
+static struct ccase *
+car_translate (struct ccase *input, void *car_)
 {
   struct casereader_append_rank *car = car_;
 
@@ -321,16 +311,16 @@ car_translate (struct ccase *input, struct ccase *output,  void *car_)
 
       do
        {
-         struct ccase c;
-         if ( ! casereader_peek (car->clone, car->n + ++k, &c))
+         struct ccase *c = casereader_peek (car->clone, car->n + ++k);
+         if (c == NULL)
            break;
-         vxx = case_data (&c, car->var)->f;
+         vxx = case_data (c, car->var)->f;
 
          if ( vxx == value)
            {
              if (car->weight)
                {
-                 double w = case_data (&c, car->weight)->f;
+                 double w = case_data (c, car->weight)->f;
 
                  if ( car->err && w < 0 )
                    *car->err |= RANK_ERR_NEGATIVE_WEIGHT;
@@ -341,7 +331,7 @@ car_translate (struct ccase *input, struct ccase *output,  void *car_)
                weight += 1.0;
              car->n_common++;
            }
-         case_destroy (&c);
+          case_unref (c);
        }
       while (vxx == value);
       car->mean_rank = car->cc + (weight + 1) / 2.0;
@@ -355,11 +345,10 @@ car_translate (struct ccase *input, struct ccase *output,  void *car_)
 
   car->n++;
 
-  case_nullify (output);
-  case_move (output, input);
-  case_resize (output, car->value_ofs + 1);
-  case_data_rw_idx (output, car->value_ofs)->f = car->mean_rank ;
+  input = case_unshare_and_resize (input, car->value_ofs + 1);
+  case_data_rw_idx (input, car->value_ofs)->f = car->mean_rank ;
   car->prev_value = value;
+  return input;
 }
 
 
index ee7facb769dbf9a26dc96d717f1249a7fe44879b..3d27a9192a79bd63466e25e2059ce91824e94241 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -43,18 +43,17 @@ struct casereader
 
 static void insert_shim (struct casereader *);
 
-/* Creates a new case in C and reads the next case from READER
-   into it.  The caller owns C and must destroy C when its data
-   is no longer needed.  Return true if successful, false when
-   cases have been exhausted or upon detection of an I/O error.
-   In the latter case, C is set to the null case.
+/* Reads and returns the next case from READER.  The caller owns
+   the returned case and must call case_unref on it when its data
+   is no longer needed.  Returns a null pointer if cases have
+   been exhausted or upon detection of an I/O error.
 
    The case returned is effectively consumed: it can never be
    read again through READER.  If this is inconvenient, READER
    may be cloned in advance with casereader_clone, or
    casereader_peek may be used instead. */
-bool
-casereader_read (struct casereader *reader, struct ccase *c)
+struct ccase *
+casereader_read (struct casereader *reader)
 {
   if (reader->case_cnt != 0)
     {
@@ -69,17 +68,18 @@ casereader_read (struct casereader *reader, struct ccase *c)
          case_cnt after calling ->read, then this would actually
          drop two cases from case_cnt instead of one, and we'd
          lose the last case in the casereader. */
+      struct ccase *c;
       if (reader->case_cnt != CASENUMBER_MAX)
         reader->case_cnt--;
-      if (reader->class->read (reader, reader->aux, c))
+      c = reader->class->read (reader, reader->aux);
+      if (c != NULL)
         {
           assert (case_get_value_cnt (c) >= reader->value_cnt);
-          return true;
+          return c;
         }
     }
   reader->case_cnt = 0;
-  case_nullify (c);
-  return false;
+  return NULL;
 }
 
 /* Destroys READER.
@@ -160,27 +160,27 @@ casereader_swap (struct casereader *a, struct casereader *b)
     }
 }
 
-/* Creates a new case in C and reads the (IDX + 1)'th case from
-   READER into it.  The caller owns C and must destroy C when its
-   data is no longer needed.  Return true if successful, false
-   when cases have been exhausted or upon detection of an I/O
-   error.  In the latter case, C is set to the null case. */
-bool
-casereader_peek (struct casereader *reader, casenumber idx, struct ccase *c)
+/* Reads and returns the (IDX + 1)'th case from READER.  The
+   caller owns the returned case and must call case_unref on it
+   when it is no longer needed.  Returns a null pointer if cases
+   have been exhausted or upon detection of an I/O error. */
+struct ccase *
+casereader_peek (struct casereader *reader, casenumber idx)
 {
   if (idx < reader->case_cnt)
     {
+      struct ccase *c;
       if (reader->class->peek == NULL)
         insert_shim (reader);
-      if (reader->class->peek (reader, reader->aux, idx, c))
-        return true;
+      c = reader->class->peek (reader, reader->aux, idx);
+      if (c != NULL)
+        return c;
       else if (casereader_error (reader))
         reader->case_cnt = 0;
     }
   if (reader->case_cnt > idx)
     reader->case_cnt = idx;
-  case_nullify (c);
-  return false;
+  return NULL;
 }
 
 /* Returns true if no cases remain to be read from READER, or if
@@ -191,13 +191,18 @@ casereader_peek (struct casereader *reader, casenumber idx, struct ccase *c)
 bool
 casereader_is_empty (struct casereader *reader)
 {
-  struct ccase c;
-  if (reader->case_cnt == 0 || !casereader_peek (reader, 0, &c))
+  if (reader->case_cnt == 0)
     return true;
   else
     {
-      case_destroy (&c);
-      return false;
+      struct ccase *c = casereader_peek (reader, 0);
+      if (c == NULL)
+        return true;
+      else
+        {
+          case_unref (c);
+          return false;
+        }
     }
 }
 
@@ -263,11 +268,11 @@ casereader_count_cases (struct casereader *reader)
   if (reader->case_cnt == CASENUMBER_MAX)
     {
       casenumber n_cases = 0;
-      struct ccase c;
+      struct ccase *c;
 
       struct casereader *clone = casereader_clone (reader);
 
-      for (; casereader_read (clone, &c); case_destroy (&c))
+      for (; (c = casereader_read (clone)) != NULL; case_unref (c))
         n_cases++;
 
       casereader_destroy (clone);
@@ -289,12 +294,12 @@ casereader_get_value_cnt (struct casereader *reader)
 void
 casereader_transfer (struct casereader *reader, struct casewriter *writer)
 {
-  struct ccase c;
+  struct ccase *c;
 
   taint_propagate (casereader_get_taint (reader),
                    casewriter_get_taint (writer));
-  while (casereader_read (reader, &c))
-    casewriter_write (writer, &c);
+  while ((c = casereader_read (reader)) != NULL)
+    casewriter_write (writer, c);
   casereader_destroy (reader);
 }
 
@@ -475,22 +480,20 @@ advance_random_reader (struct casereader *reader,
 }
 
 /* struct casereader_class "read" function for random reader. */
-static bool
-random_reader_read (struct casereader *reader, void *br_, struct ccase *c)
+static struct ccase *
+random_reader_read (struct casereader *reader, void *br_)
 {
   struct random_reader *br = br_;
   struct random_reader_shared *shared = br->shared;
-
-  if (shared->class->read (reader, shared->aux,
-                           br->offset - shared->min_offset, c))
+  struct ccase *c = shared->class->read (reader, shared->aux,
+                                         br->offset - shared->min_offset);
+  if (c != NULL)
     {
       br->offset++;
       heap_changed (shared->readers, &br->heap_node);
       advance_random_reader (reader, shared);
-      return true;
     }
-  else
-    return false;
+  return c;
 }
 
 /* struct casereader_class "destroy" function for random
@@ -529,15 +532,14 @@ random_reader_clone (struct casereader *reader, void *br_)
 }
 
 /* struct casereader_class "peek" function for random reader. */
-static bool
-random_reader_peek (struct casereader *reader, void *br_,
-                    casenumber idx, struct ccase *c)
+static struct ccase *
+random_reader_peek (struct casereader *reader, void *br_, casenumber idx)
 {
   struct random_reader *br = br_;
   struct random_reader_shared *shared = br->shared;
 
   return shared->class->read (reader, shared->aux,
-                              br->offset - shared->min_offset + idx, c);
+                              br->offset - shared->min_offset + idx);
 }
 
 /* Casereader class for random reader. */
@@ -607,24 +609,27 @@ prime_buffer (struct shim *b, casenumber case_cnt)
 {
   while (casewindow_get_case_cnt (b->window) < case_cnt)
     {
-      struct ccase tmp;
-      if (!casereader_read (b->subreader, &tmp))
+      struct ccase *tmp = casereader_read (b->subreader);
+      if (tmp == NULL)
         return false;
-      casewindow_push_head (b->window, &tmp);
+      casewindow_push_head (b->window, tmp);
     }
   return true;
 }
 
 /* Reads the case at the given 0-based OFFSET from the front of
-   the window into C.  Returns true if successful, false if
-   OFFSET is beyond the end of file or upon I/O error. */
-static bool
+   the window into C.  Returns the case if successful, or a null
+   pointer if OFFSET is beyond the end of file or upon I/O error.
+   The caller must call case_unref() on the returned case when it
+   is no longer needed. */
+static struct ccase *
 shim_read (struct casereader *reader UNUSED, void *b_,
-           casenumber offset, struct ccase *c)
+           casenumber offset)
 {
   struct shim *b = b_;
-  return (prime_buffer (b, offset + 1)
-          && casewindow_get_case (b->window, offset, c));
+  if (!prime_buffer (b, offset + 1))
+    return NULL;
+  return casewindow_get_case (b->window, offset);
 }
 
 /* Destroys B. */
index 3df80cb08fb8d38acc302e0654a0217dd666287a..deab5641661ec111d6751254f77c73ca77200550 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -59,7 +59,7 @@ struct dictionary;
 struct casereader;
 struct casewriter;
 
-bool casereader_read (struct casereader *, struct ccase *);
+struct ccase *casereader_read (struct casereader *);
 bool casereader_destroy (struct casereader *);
 
 struct casereader *casereader_clone (const struct casereader *);
@@ -68,8 +68,7 @@ void casereader_split (struct casereader *,
 struct casereader *casereader_rename (struct casereader *);
 void casereader_swap (struct casereader *, struct casereader *);
 
-bool casereader_peek (struct casereader *, casenumber, struct ccase *)
-     WARN_UNUSED_RESULT;
+struct ccase *casereader_peek (struct casereader *, casenumber);
 bool casereader_is_empty (struct casereader *);
 
 bool casereader_error (const struct casereader *);
@@ -107,9 +106,8 @@ casereader_create_counter (struct casereader *, casenumber *counter,
 
 struct casereader *
 casereader_create_translator (struct casereader *, size_t output_value_cnt,
-                              void (*translate) (struct ccase *input,
-                                                 struct ccase *output,
-                                                 void *aux),
+                              struct ccase *(*translate) (struct ccase *,
+                                                          void *aux),
                               bool (*destroy) (void *aux),
                               void *aux);
 
index 0d735c4dc3ff909c41278df40b5179bdb3dbd2cd..d2be9cfaad3b2a6a0653834dae5b173f0e93568a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -52,7 +52,7 @@ struct casewindow_class
     void (*destroy) (void *aux);
     void (*push_head) (void *aux, struct ccase *);
     void (*pop_tail) (void *aux, casenumber cnt);
-    bool (*get_case) (void *aux, casenumber ofs, struct ccase *);
+    struct ccase *(*get_case) (void *aux, casenumber ofs);
     casenumber (*get_case_cnt) (const void *aux);
   };
 
@@ -120,11 +120,11 @@ casewindow_to_disk (struct casewindow *old)
   new = do_casewindow_create (taint_clone (old->taint), old->value_cnt, 0);
   while (casewindow_get_case_cnt (old) > 0 && !casewindow_error (new))
     {
-      struct ccase c;
-      if (!casewindow_get_case (old, 0, &c))
+      struct ccase *c = casewindow_get_case (old, 0);
+      if (c == NULL)
         break;
       casewindow_pop_tail (old, 1);
-      casewindow_push_head (new, &c);
+      casewindow_push_head (new, c);
     }
   casewindow_swap (old, new);
   casewindow_destroy (new);
@@ -147,7 +147,7 @@ casewindow_push_head (struct casewindow *cw, struct ccase *c)
         }
     }
   else
-    case_destroy (c);
+    case_unref (c);
 }
 
 /* Deletes CASE_CNT cases at the tail of casewindow CW. */
@@ -158,23 +158,19 @@ casewindow_pop_tail (struct casewindow *cw, casenumber case_cnt)
     cw->class->pop_tail (cw->aux, case_cnt);
 }
 
-/* Copies the case that is CASE_IDX cases away from CW's tail
-   into C.  Returns true if successful, false on an I/O error or
-   if CW is otherwise tainted.  On failure, nullifies case C. */
-bool
-casewindow_get_case (const struct casewindow *cw_, casenumber case_idx,
-                     struct ccase *c)
+/* Returns the case that is CASE_IDX cases away from CW's tail
+   into C, or a null pointer on an I/O error or if CW is
+   otherwise tainted.  The caller must call case_unref() on the
+   returned case when it is no longer needed. */
+struct ccase *
+casewindow_get_case (const struct casewindow *cw_, casenumber case_idx)
 {
   struct casewindow *cw = (struct casewindow *) cw_;
 
   assert (case_idx >= 0 && case_idx < casewindow_get_case_cnt (cw));
-  if (!casewindow_error (cw))
-    return cw->class->get_case (cw->aux, case_idx, c);
-  else
-    {
-      case_nullify (c);
-      return false;
-    }
+  if (casewindow_error (cw))
+    return NULL;
+  return cw->class->get_case (cw->aux, case_idx);
 }
 
 /* Returns the number of cases in casewindow CW. */
@@ -218,7 +214,7 @@ casewindow_get_taint (const struct casewindow *cw)
 struct casewindow_memory
   {
     struct deque deque;
-    struct ccase *cases;
+    struct ccase **cases;
   };
 
 static void *
@@ -234,7 +230,7 @@ casewindow_memory_destroy (void *cwm_)
 {
   struct casewindow_memory *cwm = cwm_;
   while (!deque_is_empty (&cwm->deque))
-    case_destroy (&cwm->cases[deque_pop_front (&cwm->deque)]);
+    case_unref (cwm->cases[deque_pop_front (&cwm->deque)]);
   free (cwm->cases);
   free (cwm);
 }
@@ -245,7 +241,7 @@ casewindow_memory_push_head (void *cwm_, struct ccase *c)
   struct casewindow_memory *cwm = cwm_;
   if (deque_is_full (&cwm->deque))
     cwm->cases = deque_expand (&cwm->deque, cwm->cases, sizeof *cwm->cases);
-  case_move (&cwm->cases[deque_push_back (&cwm->deque)], c);
+  cwm->cases[deque_push_back (&cwm->deque)] = c;
 }
 
 static void
@@ -254,15 +250,14 @@ casewindow_memory_pop_tail (void *cwm_, casenumber case_cnt)
   struct casewindow_memory *cwm = cwm_;
   assert (deque_count (&cwm->deque) >= case_cnt);
   while (case_cnt-- > 0)
-    case_destroy (&cwm->cases[deque_pop_front (&cwm->deque)]);
+    case_unref (cwm->cases[deque_pop_front (&cwm->deque)]);
 }
 
-static bool
-casewindow_memory_get_case (void *cwm_, casenumber ofs, struct ccase *c)
+static struct ccase *
+casewindow_memory_get_case (void *cwm_, casenumber ofs)
 {
   struct casewindow_memory *cwm = cwm_;
-  case_clone (c, &cwm->cases[deque_front (&cwm->deque, ofs)]);
-  return true;
+  return case_ref (cwm->cases[deque_front (&cwm->deque, ofs)]);
 }
 
 static casenumber
@@ -325,11 +320,11 @@ casewindow_file_pop_tail (void *cwf_, casenumber cnt)
     cwf->head = cwf->tail = 0;
 }
 
-static bool
-casewindow_file_get_case (void *cwf_, casenumber ofs, struct ccase *c)
+static struct ccase *
+casewindow_file_get_case (void *cwf_, casenumber ofs)
 {
   struct casewindow_file *cwf = cwf_;
-  return case_tmpfile_get_case (cwf->file, cwf->tail + ofs, c);
+  return case_tmpfile_get_case (cwf->file, cwf->tail + ofs);
 }
 
 static casenumber
index c3971231afe2d1ed5ac5f89e9b5b61e719505212..f0a200f449de014638d8114ce9b50cb13a4fccb8 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -37,8 +37,8 @@ bool casewindow_destroy (struct casewindow *);
 
 void casewindow_push_head (struct casewindow *, struct ccase *);
 void casewindow_pop_tail (struct casewindow *, casenumber cnt);
-bool casewindow_get_case (const struct casewindow *, casenumber case_idx,
-                          struct ccase *);
+struct ccase *casewindow_get_case (const struct casewindow *,
+                                   casenumber case_idx);
 size_t casewindow_get_value_cnt (const struct casewindow *);
 casenumber casewindow_get_case_cnt (const struct casewindow *);
 
index 8298af465da9d88640fe813f6a12309c6effd036..1680fe28303c5f1fa4dd6d8887954a39b494abc9 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 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
@@ -23,7 +23,8 @@ struct casewriter_class
   {
     /* Mandatory.
 
-       Writes case C to WRITER.  Destroys C before returning.
+       Writes case C to WRITER.  Ownership of C is transferred to
+       WRITER.
 
        If an I/O error occurs, this function should call
        casewriter_force_error on WRITER.  Some I/O error
index c630b44cda397dfffccd980c9d3ecb65255e91dc..a19533d65d330b6f443b308522e88d61b25687f6 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -29,7 +29,7 @@ struct casewriter_translator
   {
     struct casewriter *subwriter;
 
-    void (*translate) (struct ccase *input, struct ccase *output, void *aux);
+    struct ccase *(*translate) (struct ccase *, void *aux);
     bool (*destroy) (void *aux);
     void *aux;
   };
@@ -37,10 +37,15 @@ struct casewriter_translator
 static const struct casewriter_class casewriter_translator_class;
 
 /* Creates and returns a new casewriter whose cases are passed
-   through TRANSLATE, which must create case OUTPUT, with
-   OUTPUT_VALUE_CNT values, and populate it based on INPUT and
-   auxiliary data AUX.  The translated cases are then written to
-   SUBWRITER.  TRANSLATE must also destroy INPUT.
+   through TRANSLATE, which must return a case with
+   OUTPUT_VALUE_CNT values, based on INPUT and auxiliary data
+   AUX.  (TRANSLATE may also return a null pointer, in which case
+   no case is written to the output.)  The translated cases are
+   then written to SUBWRITER.
+
+   TRANSLATE takes ownership of each case passed to it.  Thus, it
+   should either unref each case and return a new case, or
+   (unshare and then) modify and return the same case.
 
    When the translating casewriter is destroyed, DESTROY will be
    called to allow any state maintained by TRANSLATE to be freed.
@@ -51,9 +56,8 @@ static const struct casewriter_class casewriter_translator_class;
 struct casewriter *
 casewriter_create_translator (struct casewriter *subwriter,
                               size_t translated_value_cnt,
-                              void (*translate) (struct ccase *input,
-                                                 struct ccase *output,
-                                                 void *aux),
+                              struct ccase *(*translate) (struct ccase *,
+                                                          void *aux),
                               bool (*destroy) (void *aux),
                               void *aux)
 {
@@ -75,10 +79,9 @@ casewriter_translator_write (struct casewriter *writer UNUSED,
                              void *ct_, struct ccase *c)
 {
   struct casewriter_translator *ct = ct_;
-  struct ccase tmp;
-
-  ct->translate (c, &tmp, ct->aux);
-  casewriter_write (ct->subwriter, &tmp);
+  c = ct->translate (c, ct->aux);
+  if (c != NULL)
+    casewriter_write (ct->subwriter, c);
 }
 
 static void
index 4461d85e84cfc191821746df34e44b02dfc0f4ef..56e6c291cbb4fb7722a310eeb504b20bb58a37d5 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -250,18 +250,19 @@ casewriter_window_convert_to_reader (struct casewriter *writer UNUSED,
   return reader;
 }
 
-/* Reads the case at the given 0-based OFFSET from the front of
-   WINDOW into C.  Returns true if successful, false if
-   OFFSET is beyond the end of file or upon I/O error. */
-static bool
+/* Reads and returns the case at the given 0-based OFFSET from
+   the front of WINDOW into C.  Returns a null pointer if OFFSET
+   is beyond the end of file or upon I/O error.  The caller must
+   call case_unref() on the returned case when it is no longer
+   needed.*/
+static struct ccase *
 casereader_window_read (struct casereader *reader UNUSED, void *window_,
-                        casenumber offset, struct ccase *c)
+                        casenumber offset)
 {
   struct casewindow *window = window_;
   if (offset >= casewindow_get_case_cnt (window))
-    return false;
-  else
-    return casewindow_get_case (window, offset, c);
+    return NULL;
+  return casewindow_get_case (window, offset);
 }
 
 /* Destroys casewindow reader WINDOW. */
index a92c417680116ffbfc438e52877b64f74f62e1e3..05ef707246060eb215e0b880d6c4e9b0117013d1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -43,9 +43,8 @@ struct casewriter *autopaging_writer_create (size_t value_cnt);
 \f
 struct casewriter *
 casewriter_create_translator (struct casewriter *, size_t translated_value_cnt,
-                              void (*translate) (struct ccase *input,
-                                                 struct ccase *output,
-                                                 void *aux),
+                              struct ccase *(*translate) (struct ccase *input,
+                                                          void *aux),
                               bool (*destroy) (void *aux),
                               void *aux);
 
index fd07ed30e71e48647462e163b3e6991e83e42f54..83a2a677e3b55a671a10f71d5347fb2b4b312b07 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -389,21 +389,22 @@ datasheet_move_columns (struct datasheet *ds,
   axis_move (ds->columns, old_start, new_start, cnt);
 }
 
-/* Retrieves the contents of the given ROW in datasheet DS into
-   newly created case C.  Returns true if successful, false on
-   I/O error. */
-bool
-datasheet_get_row (const struct datasheet *ds, casenumber row, struct ccase *c)
+/* Retrieves and returns the contents of the given ROW in
+   datasheet DS.  The caller owns the returned case and must
+   unref it when it is no longer needed.  Returns a null pointer
+   on I/O error. */
+struct ccase *
+datasheet_get_row (const struct datasheet *ds, casenumber row)
 {
   size_t column_cnt = datasheet_get_column_cnt (ds);
-  case_create (c, column_cnt);
+  struct ccase *c = case_create (column_cnt);
   if (rw_case ((struct datasheet *) ds, OP_READ,
                row, 0, column_cnt, case_data_all_rw (c)))
-    return true;
+    return c;
   else
     {
-      case_destroy (c);
-      return false;
+      case_unref (c);
+      return NULL;
     }
 }
 
@@ -417,7 +418,7 @@ datasheet_put_row (struct datasheet *ds, casenumber row, struct ccase *c)
   size_t column_cnt = datasheet_get_column_cnt (ds);
   bool ok = rw_case (ds, OP_WRITE, row, 0, column_cnt,
                      (union value *) case_data_all (c));
-  case_destroy (c);
+  case_unref (c);
   return ok;
 }
 
@@ -445,13 +446,15 @@ datasheet_put_value (struct datasheet *ds, casenumber row, size_t column,
                   (union value *) value);
 }
 
-/* Inserts the CNT cases at C, which are destroyed, into
-   datasheet DS just before row BEFORE.  Returns true if
-   successful, false on I/O error.  On failure, datasheet DS is
-   not modified. */
+/* Inserts the CNT cases at C into datasheet DS just before row
+   BEFORE.  Returns true if successful, false on I/O error.  On
+   failure, datasheet DS is not modified.
+
+   Regardless of success, this function unrefs all of the cases
+   in C. */
 bool
 datasheet_insert_rows (struct datasheet *ds,
-                       casenumber before, struct ccase c[],
+                       casenumber before, struct ccase *c[],
                        casenumber cnt)
 {
   casenumber added = 0;
@@ -476,10 +479,10 @@ datasheet_insert_rows (struct datasheet *ds,
 
       /* Initialize the new rows. */
       for (i = 0; i < phy_cnt; i++)
-        if (!datasheet_put_row (ds, before + i, &c[i]))
+        if (!datasheet_put_row (ds, before + i, c[i]))
           {
             while (++i < cnt)
-              case_destroy (&c[i]);
+              case_unref (c[i]);
             datasheet_delete_rows (ds, before - added, phy_cnt + added);
             return false;
           }
@@ -540,20 +543,20 @@ datasheet_make_reader (struct datasheet *ds)
 }
 
 /* "read" function for the datasheet random casereader. */
-static bool
+static struct ccase *
 datasheet_reader_read (struct casereader *reader UNUSED, void *ds_,
-                       casenumber case_idx, struct ccase *c)
+                       casenumber case_idx)
 {
   struct datasheet *ds = ds_;
-  if (case_idx >= datasheet_get_row_cnt (ds))
-    return false;
-  else if (datasheet_get_row (ds, case_idx, c))
-    return true;
-  else
+  if (case_idx < datasheet_get_row_cnt (ds))
     {
-      taint_set_taint (ds->taint);
-      return false;
+      struct ccase *c = datasheet_get_row (ds, case_idx);
+      if (c == NULL)
+        taint_set_taint (ds->taint);
+      return c;
     }
+  else
+    return NULL;
 }
 
 /* "destroy" function for the datasheet random casereader. */
@@ -1136,15 +1139,12 @@ source_read (const struct source *source,
     return sparse_cases_read (source->data, row, column, values, value_cnt);
   else
     {
-      struct ccase c;
-      bool ok;
-
-      assert (source->backing != NULL);
-      ok = casereader_peek (source->backing, row, &c);
+      struct ccase *c = casereader_peek (source->backing, row);
+      bool ok = c != NULL;
       if (ok)
         {
-          case_copy_out (&c, column, values, value_cnt);
-          case_destroy (&c);
+          case_copy_out (c, column, values, value_cnt);
+          case_unref (c);
         }
       return ok;
     }
@@ -1169,9 +1169,10 @@ source_write (struct source *source,
     ok = sparse_cases_write (source->data, row, column, values, value_cnt);
   else
     {
-      struct ccase c;
+      struct ccase *c;
+
       if (row < source->backing_rows)
-        ok = casereader_peek (source->backing, row, &c);
+        c = case_unshare (casereader_peek (source->backing, row));
       else
         {
           /* It's not one of the backed rows.  Ideally, this
@@ -1182,15 +1183,16 @@ source_write (struct source *source,
              levels, so that we in fact usually write the full
              contents of new, unbacked rows in multiple calls to
              this function.  Make this work. */
-          case_create (&c, column_cnt);
-          ok = true;
+          c = case_create (column_cnt);
         }
+      ok = c != NULL;
+
       if (ok)
         {
-          case_copy_in (&c, column, values, value_cnt);
+          case_copy_in (c, column, values, value_cnt);
           ok = sparse_cases_write (source->data, row, 0,
-                                   case_data_all (&c), column_cnt);
-          case_destroy (&c);
+                                   case_data_all (c), column_cnt);
+          case_unref (c);
         }
     }
   return ok;
index 2a05fe0da516bef80ea9ee7abafb7b38c33e4892..860f236ec33af74b1ba8f53be1d5108a40644501 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -50,7 +50,7 @@ void datasheet_move_columns (struct datasheet *,
 /* Rows. */
 casenumber datasheet_get_row_cnt (const struct datasheet *);
 bool datasheet_insert_rows (struct datasheet *,
-                            casenumber before, struct ccase[],
+                            casenumber before, struct ccase *[],
                             casenumber cnt);
 void datasheet_delete_rows (struct datasheet *,
                             casenumber first, casenumber cnt);
@@ -59,7 +59,7 @@ void datasheet_move_rows (struct datasheet *,
                           size_t cnt);
 
 /* Data. */
-bool datasheet_get_row (const struct datasheet *, casenumber, struct ccase *);
+struct ccase *datasheet_get_row (const struct datasheet *, casenumber);
 bool datasheet_put_row (struct datasheet *, casenumber, struct ccase *);
 bool datasheet_get_value (const struct datasheet *, casenumber, size_t column,
                           union value *, int width);
index 86c8e17e467d45c3cf7edac34166b20357cba62f..14afd60e53be5f86e01963d6f0a9aa08927e5de3 100644 (file)
@@ -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
+
index b4231d2f87178b841f85cf62d69a76e15b871b5e..d34bd4196fea046db722197aa403db964a423deb 100644 (file)
@@ -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 */
index 522176640489c87ec57027115582cbb9bc26d617..5a0c75ede293a21052228a87b295a070398f3e1f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -60,8 +60,7 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict)
 
 static void gnm_file_casereader_destroy (struct casereader *, void *);
 
-static bool gnm_file_casereader_read (struct casereader *, void *,
-                                     struct ccase *);
+static struct ccase *gnm_file_casereader_read (struct casereader *, void *);
 
 static const struct casereader_class gnm_file_casereader_class =
   {
@@ -172,7 +171,7 @@ struct gnumeric_reader
 
   size_t value_cnt;
   struct dictionary *dict;
-  struct ccase first_case;
+  struct ccase *first_case;
   bool used_first_case;
 };
 
@@ -193,7 +192,7 @@ gnm_file_casereader_destroy (struct casereader *reader UNUSED, void *r_)
     xmlFreeTextReader (r->xtr);
 
   if ( ! r->used_first_case )
-    case_destroy (&r->first_case);
+    case_unref (r->first_case);
 
   free (r);
 }
@@ -537,15 +536,15 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict)
       goto error;
     }
 
-  case_create (&r->first_case, r->value_cnt);
-  memset (case_data_rw_idx (&r->first_case, 0)->s,
+  r->first_case = case_create (r->value_cnt);
+  memset (case_data_rw_idx (r->first_case, 0)->s,
          ' ', MAX_SHORT_STRING * r->value_cnt);
 
   for ( i = 0 ; i < n_var_specs ; ++i )
     {
       const struct variable *var = dict_get_var (r->dict, i);
 
-      convert_xml_string_to_value (&r->first_case, var,
+      convert_xml_string_to_value (r->first_case, var,
                                   var_spec[i].first_value);
     }
 
@@ -580,12 +579,12 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict)
 };
 
 
-/* Reads one case from READER's file into C.  Returns true only
-   if successful. */
-static bool
-gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_,
-                          struct ccase *c)
+/* Reads and returns one case from READER's file.  Returns a null
+   pointer on failure. */
+static struct ccase *
+gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_)
 {
+  struct ccase *c;
   int ret = 0;
 
   struct gnumeric_reader *r = r_;
@@ -593,12 +592,11 @@ gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_,
 
   if ( !r->used_first_case )
     {
-      *c = r->first_case;
       r->used_first_case = true;
-      return true;
+      return r->first_case;
     }
 
-  case_create (c, r->value_cnt);
+  c = case_create (r->value_cnt);
 
   memset (case_data_rw_idx (c, 0)->s, ' ', MAX_SHORT_STRING * r->value_cnt);
 
@@ -632,7 +630,13 @@ gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_,
 
     }
 
-  return (ret == 1);
+  if (ret == 1)
+    return c;
+  else
+    {
+      case_unref (c);
+      return NULL;
+    }
 }
 
 
index 2cb8911fe29770559eee3c7c2ea702e88a38b9f5..65d10aea2477640a826077a7da01c17f78fbf665 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -117,13 +117,12 @@ instantiate_lazy_casereader (struct casereader *reader,
   casereader_destroy (subreader);
 }
 
-static bool
-lazy_casereader_read (struct casereader *reader, void *lc_,
-                      struct ccase *c)
+static struct ccase *
+lazy_casereader_read (struct casereader *reader, void *lc_)
 {
   struct lazy_casereader *lc = lc_;
   instantiate_lazy_casereader (reader, lc);
-  return casereader_read (reader, c);
+  return casereader_read (reader);
 }
 
 static void
@@ -143,13 +142,12 @@ lazy_casereader_clone (struct casereader *reader, void *lc_)
   return casereader_clone (reader);
 }
 
-static bool
-lazy_casereader_peek (struct casereader *reader, void *lc_,
-                      casenumber idx, struct ccase *c)
+static struct ccase *
+lazy_casereader_peek (struct casereader *reader, void *lc_, casenumber idx)
 {
   struct lazy_casereader *lc = lc_;
   instantiate_lazy_casereader (reader, lc);
-  return casereader_peek (reader, idx, c);
+  return casereader_peek (reader, idx);
 }
 
 static const struct casereader_class lazy_casereader_class =
index 52c0cc8edab5dca9a59b142d83cf9c3466489a3e..7e65c28bdf51c11b54f1f6ddd9eced26670b6197 100644 (file)
@@ -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
@@ -814,28 +814,30 @@ read_documents (struct pfm_reader *r, struct dictionary *dict)
     }
 }
 
-/* Reads one case from portable file R into C. */
-static bool
-por_file_casereader_read (struct casereader *reader, void *r_, struct ccase *c)
+/* Reads and returns one case from portable file R.  Returns a
+   null pointer on failure. */
+static struct ccase *
+por_file_casereader_read (struct casereader *reader, void *r_)
 {
   struct pfm_reader *r = r_;
+  struct ccase *volatile c;
   size_t i;
   size_t idx;
 
-  case_create (c, casereader_get_value_cnt (reader));
+  c = case_create (casereader_get_value_cnt (reader));
   setjmp (r->bail_out);
   if (!r->ok)
     {
       casereader_force_error (reader);
-      case_destroy (c);
-      return false;
+      case_unref (c);
+      return NULL;
     }
 
   /* Check for end of file. */
   if (r->cc == 'Z')
     {
-      case_destroy (c);
-      return false;
+      case_unref (c);
+      return NULL;
     }
 
   idx = 0;
@@ -857,7 +859,7 @@ por_file_casereader_read (struct casereader *reader, void *r_, struct ccase *c)
         }
     }
 
-  return true;
+  return c;
 }
 
 /* Returns true if FILE is an SPSS portable file,
index f227fd9a7761b1381c04c3598281cad5de114aae..326514f9a78e58adc9ebd46205565a0262e394f5 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -34,7 +34,6 @@ struct pfm_read_info
 
 struct dictionary;
 struct file_handle;
-struct ccase;
 struct casereader *pfm_open_reader (struct file_handle *,
                                     struct dictionary **,
                                     struct pfm_read_info *);
index 8a27f6b785ccc548d5a14436cfe221ee7476d3e6..773969302ebcb9ddc3b06fea93aa1da6c66c313c 100644 (file)
@@ -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
@@ -463,7 +463,7 @@ por_file_casewriter_write (struct casewriter *writer, void *w_,
   else
     casewriter_force_error (writer);
 
-  case_destroy (c);
+  case_unref (c);
 }
 
 static void
index b018a4f4206ad47611823c81891a5a30c33d8b6e..04eaaa2c724865a9887c043f7b3a7bb49ed71f4a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -38,7 +38,6 @@ struct pfm_write_options
 
 struct file_handle;
 struct dictionary;
-struct ccase;
 struct casewriter *pfm_open_writer (struct file_handle *, struct dictionary *,
                                     struct pfm_write_options);
 struct pfm_write_options pfm_writer_default_options (void);
index 98414a2b0478dbb5e44f306e0f99d90684b86003..91e185a45a43f3d78802338d6b26536f0a9dc6b0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 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
@@ -79,7 +79,7 @@ struct dataset {
   /* Cases just before ("lagging") the current one. */
   int n_lag;                   /* Number of cases to lag. */
   struct deque lag;             /* Deque of lagged cases. */
-  struct ccase *lag_cases;      /* Lagged cases managed by deque. */
+  struct ccase **lag_cases;     /* Lagged cases managed by deque. */
 
   /* Procedure data. */
   enum
@@ -203,15 +203,15 @@ proc_is_open (const struct dataset *ds)
 }
 
 /* "read" function for procedure casereader. */
-static bool
-proc_casereader_read (struct casereader *reader UNUSED, void *ds_,
-                      struct ccase *c)
+static struct ccase *
+proc_casereader_read (struct casereader *reader UNUSED, void *ds_)
 {
   struct dataset *ds = ds_;
   enum trns_result retval = TRNS_DROP_CASE;
+  struct ccase *c;
 
   assert (ds->proc_state == PROC_OPEN);
-  for (;;)
+  for (; ; case_unref (c))
     {
       casenumber case_nr;
 
@@ -219,58 +219,47 @@ proc_casereader_read (struct casereader *reader UNUSED, void *ds_,
       if (retval == TRNS_ERROR)
         ds->ok = false;
       if (!ds->ok)
-        return false;
+        return NULL;
 
       /* Read a case from source. */
-      if (!casereader_read (ds->source, c))
-        return false;
-      case_resize (c, dict_get_next_value_idx (ds->dict));
+      c = casereader_read (ds->source);
+      if (c == NULL)
+        return NULL;
+      c = case_unshare_and_resize (c, dict_get_next_value_idx (ds->dict));
       caseinit_init_vars (ds->caseinit, c);
 
       /* Execute permanent transformations.  */
       case_nr = ds->cases_written + 1;
       retval = trns_chain_execute (ds->permanent_trns_chain, TRNS_CONTINUE,
-                                   c, case_nr);
+                                   &c, case_nr);
       caseinit_update_left_vars (ds->caseinit, c);
       if (retval != TRNS_CONTINUE)
-        {
-          case_destroy (c);
-          continue;
-        }
+        continue;
 
       /* Write case to collection of lagged cases. */
       if (ds->n_lag > 0)
         {
           while (deque_count (&ds->lag) >= ds->n_lag)
-            case_destroy (&ds->lag_cases[deque_pop_back (&ds->lag)]);
-          case_clone (&ds->lag_cases[deque_push_front (&ds->lag)], c);
+            case_unref (ds->lag_cases[deque_pop_back (&ds->lag)]);
+          ds->lag_cases[deque_push_front (&ds->lag)] = case_ref (c);
         }
 
       /* Write case to replacement active file. */
       ds->cases_written++;
       if (ds->sink != NULL)
-        {
-          struct ccase tmp;
-          if (ds->compactor != NULL)
-            case_map_execute (ds->compactor, c, &tmp);
-          else
-            case_clone (&tmp, c);
-          casewriter_write (ds->sink, &tmp);
-        }
+        casewriter_write (ds->sink,
+                          case_map_execute (ds->compactor, case_ref (c)));
 
       /* Execute temporary transformations. */
       if (ds->temporary_trns_chain != NULL)
         {
           retval = trns_chain_execute (ds->temporary_trns_chain, TRNS_CONTINUE,
-                                       c, ds->cases_written);
+                                       &c, ds->cases_written);
           if (retval != TRNS_CONTINUE)
-            {
-              case_destroy (c);
-              continue;
-            }
+            continue;
         }
 
-      return true;
+      return c;
     }
 }
 
@@ -279,13 +268,13 @@ static void
 proc_casereader_destroy (struct casereader *reader, void *ds_)
 {
   struct dataset *ds = ds_;
-  struct ccase c;
+  struct ccase *c;
 
   /* Make sure transformations happen for every input case, in
      case they have side effects, and ensure that the replacement
      active file gets all the cases it should. */
-  while (casereader_read (reader, &c))
-    case_destroy (&c);
+  while ((c = casereader_read (reader)) != NULL)
+    case_unref (c);
 
   ds->proc_state = PROC_CLOSED;
   ds->ok = casereader_destroy (ds->source) && ds->ok;
@@ -306,7 +295,7 @@ proc_commit (struct dataset *ds)
 
   /* Free memory for lagged cases. */
   while (!deque_is_empty (&ds->lag))
-    case_destroy (&ds->lag_cases[deque_pop_back (&ds->lag)]);
+    case_unref (ds->lag_cases[deque_pop_back (&ds->lag)]);
   free (ds->lag_cases);
 
   /* Dictionary from before TEMPORARY becomes permanent. */
@@ -361,14 +350,14 @@ update_last_proc_invocation (struct dataset *ds)
 \f
 /* Returns a pointer to the lagged case from N_BEFORE cases before the
    current one, or NULL if there haven't been that many cases yet. */
-struct ccase *
+const struct ccase *
 lagged_case (const struct dataset *ds, int n_before)
 {
   assert (n_before >= 1);
   assert (n_before <= ds->n_lag);
 
   if (n_before <= deque_count (&ds->lag))
-    return &ds->lag_cases[deque_front (&ds->lag, n_before - 1)];
+    return ds->lag_cases[deque_front (&ds->lag, n_before - 1)];
   else
     return NULL;
 }
@@ -679,7 +668,7 @@ add_case_limit_trns (struct dataset *ds)
    *CASES_REMAINING. */
 static int
 case_limit_trns_proc (void *cases_remaining_,
-                      struct ccase *c UNUSED, casenumber case_nr UNUSED)
+                      struct ccase **c UNUSED, casenumber case_nr UNUSED)
 {
   size_t *cases_remaining = cases_remaining_;
   if (*cases_remaining > 0)
@@ -718,11 +707,11 @@ add_filter_trns (struct dataset *ds)
 /* FILTER transformation. */
 static int
 filter_trns_proc (void *filter_var_,
-                  struct ccase *c UNUSED, casenumber case_nr UNUSED)
+                  struct ccase **c UNUSED, casenumber case_nr UNUSED)
 
 {
   struct variable *filter_var = filter_var_;
-  double f = case_num (c, filter_var);
+  double f = case_num (*c, filter_var);
   return (f != 0.0 && !var_is_num_missing (filter_var, f, MV_ANY)
           ? TRNS_CONTINUE : TRNS_DROP_CASE);
 }
index 336725dfdeca934a1a315db32a666d5a17c7ac4f..5d998030a644d8d20ac2f030f90a70e685959bb6 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 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
@@ -82,7 +82,7 @@ struct dictionary *dataset_dict (const struct dataset *ds);
 const struct casereader *dataset_source (const struct dataset *ds);
 
 
-struct ccase *lagged_case (const struct dataset *ds, int n_before);
+const struct ccase *lagged_case (const struct dataset *ds, int n_before);
 void dataset_need_lag (struct dataset *ds, int n_before);
 
 #endif /* procedure.h */
index 244248a20aeecdf34bcabedbbf188047e5c9b71c..a54b9f8b3888c58320623ea1d53086bc8650a155 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 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
@@ -75,8 +75,7 @@ psql_open_reader (struct psql_read_info *info UNUSED, struct dictionary **dict U
 
 static void psql_casereader_destroy (struct casereader *reader UNUSED, void *r_);
 
-static bool psql_casereader_read (struct casereader *, void *,
-                                 struct ccase *);
+static struct ccase *psql_casereader_read (struct casereader *, void *);
 
 static const struct casereader_class psql_casereader_class =
   {
@@ -109,8 +108,7 @@ struct psql_reader
 };
 
 
-static bool set_value (struct psql_reader *r,
-                      struct ccase *cc);
+static struct ccase *set_value (struct psql_reader *r);
 
 
 
@@ -546,9 +544,8 @@ psql_casereader_destroy (struct casereader *reader UNUSED, void *r_)
 
 
 
-static bool
-psql_casereader_read (struct casereader *reader UNUSED, void *r_,
-                     struct ccase *cc)
+static struct ccase *
+psql_casereader_read (struct casereader *reader UNUSED, void *r_)
 {
   struct psql_reader *r = r_;
 
@@ -558,24 +555,24 @@ psql_casereader_read (struct casereader *reader UNUSED, void *r_,
        return false;
     }
 
-  return set_value (r, cc);
+  return set_value (r);
 }
 
-static bool
-set_value (struct psql_reader *r,
-          struct ccase *c)
+static struct ccase *
+set_value (struct psql_reader *r)
 {
-  int i;
+  struct ccase *c;
   int n_vars;
+  int i;
 
   assert (r->res);
 
   n_vars = PQnfields (r->res);
 
   if ( r->tuple >= PQntuples (r->res))
-    return false;
+    return NULL;
 
-  case_create (c, r->value_cnt);
+  c = case_create (r->value_cnt);
   memset (case_data_rw_idx (c, 0)->s, ' ', MAX_SHORT_STRING * r->value_cnt);
 
 
@@ -870,7 +867,7 @@ set_value (struct psql_reader *r,
 
   r->tuple++;
 
-  return true;
+  return c;
 }
 
 #endif
index 44531a494f5465bd439aec03bcd6044e640581c1..a5ee005efda9b521db198cdbc4dda387c1fa2646 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 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
@@ -21,7 +21,6 @@
 
 struct dictionary;
 struct file_handle;
-struct ccase;
 struct casereader *scratch_reader_open (struct file_handle *,
                                         struct dictionary **);
 
index ed88af6db4ee1a211443702de9545c251546abc7..952860cdc5887e00104be1239f089f3eaf2c71b8 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 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
@@ -99,15 +99,8 @@ scratch_writer_casewriter_write (struct casewriter *w UNUSED, void *writer_,
                                  struct ccase *c)
 {
   struct scratch_writer *writer = writer_;
-  struct ccase tmp;
-  if (writer->compactor)
-    {
-      case_map_execute (writer->compactor, c, &tmp);
-      case_destroy (c);
-    }
-  else
-    case_move (&tmp, c);
-  casewriter_write (writer->subwriter, &tmp);
+  casewriter_write (writer->subwriter,
+                    case_map_execute (writer->compactor, c));
 }
 
 /* Closes WRITER. */
index d2fda12a915c85341d304974b9eee75cc555948f..a9c7a4d9c1e8dfd96974aa142eb44a014e1dc0c8 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 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
@@ -21,7 +21,6 @@
 
 struct dictionary;
 struct file_handle;
-struct ccase;
 struct casewriter *scratch_writer_open (struct file_handle *,
                                         const struct dictionary *);
 
index 1f3fb092a12b77a0601cdce75717a4e87d883a24..13fcf7888feae74f2a2489f7ea5df3c678807a71 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <data/case.h>
 #include <data/settings.h>
 #include <data/case-tmpfile.h>
 #include <libpspp/assertion.h>
@@ -49,7 +50,7 @@ sparse_cases_create (size_t column_cnt)
   sc->column_cnt = column_cnt;
   sc->default_columns = NULL;
   sc->max_memory_cases = settings_get_workspace_cases (column_cnt);
-  sc->memory = sparse_array_create (sizeof (struct ccase));
+  sc->memory = sparse_array_create (sizeof (struct ccase *));
   sc->disk = NULL;
   sc->disk_cases = NULL;
   return sc;
@@ -76,12 +77,15 @@ sparse_cases_clone (const struct sparse_cases *old)
   if (old->memory != NULL)
     {
       unsigned long int idx;
-      struct ccase *c;
+      struct ccase **cp;
 
-      new->memory = sparse_array_create (sizeof (struct ccase));
-      for (c = sparse_array_scan (old->memory, NULL, &idx); c != NULL;
-           c = sparse_array_scan (old->memory, &idx, &idx))
-        case_clone (sparse_array_insert (new->memory, idx), c);
+      new->memory = sparse_array_create (sizeof (struct ccase *));
+      for (cp = sparse_array_scan (old->memory, NULL, &idx); cp != NULL;
+           cp = sparse_array_scan (old->memory, &idx, &idx))
+        {
+          struct ccase **ncp = sparse_array_insert (new->memory, idx);
+          *ncp = case_ref (*cp);
+        }
     }
   else
     new->memory = NULL;
@@ -98,15 +102,16 @@ sparse_cases_clone (const struct sparse_cases *old)
           unsigned long int start = range_set_node_get_start (node);
           unsigned long int end = range_set_node_get_end (node);
           unsigned long int idx;
-          struct ccase c;
-
-          for (idx = start; idx < end; idx++)
-            if (!case_tmpfile_get_case (old->disk, idx, &c)
-                || !case_tmpfile_put_case (new->disk, idx, &c))
-              {
-                sparse_cases_destroy (new);
-                return NULL;
-              }
+
+          for (idx = start; idx < end; idx++) 
+            {
+              struct ccase *c = case_tmpfile_get_case (old->disk, idx);
+              if (c == NULL || !case_tmpfile_put_case (new->disk, idx, c))
+                {
+                  sparse_cases_destroy (new);
+                  return NULL;
+                }
+            }
         }
     }
   else
@@ -127,10 +132,10 @@ sparse_cases_destroy (struct sparse_cases *sc)
       if (sc->memory != NULL)
         {
           unsigned long int idx;
-          struct ccase *c;
-          for (c = sparse_array_scan (sc->memory, NULL, &idx); c != NULL;
-               c = sparse_array_scan (sc->memory, &idx, &idx))
-            case_destroy (c);
+          struct ccase **cp;
+          for (cp = sparse_array_scan (sc->memory, NULL, &idx); cp != NULL;
+               cp = sparse_array_scan (sc->memory, &idx, &idx))
+            case_unref (*cp);
           sparse_array_destroy (sc->memory);
         }
       free (sc->default_columns);
@@ -154,7 +159,7 @@ static bool
 dump_sparse_cases_to_disk (struct sparse_cases *sc)
 {
   unsigned long int idx;
-  struct ccase *c;
+  struct ccase **cp;
 
   assert (sc->memory != NULL);
   assert (sc->disk == NULL);
@@ -162,10 +167,10 @@ dump_sparse_cases_to_disk (struct sparse_cases *sc)
   sc->disk = case_tmpfile_create (sc->column_cnt);
   sc->disk_cases = range_set_create ();
 
-  for (c = sparse_array_scan (sc->memory, NULL, &idx); c != NULL;
-       c = sparse_array_scan (sc->memory, &idx, &idx))
+  for (cp = sparse_array_scan (sc->memory, NULL, &idx); cp != NULL;
+       cp = sparse_array_scan (sc->memory, &idx, &idx))
     {
-      if (!case_tmpfile_put_case (sc->disk, idx, c))
+      if (!case_tmpfile_put_case (sc->disk, idx, *cp))
         {
           case_tmpfile_destroy (sc->disk);
           sc->disk = NULL;
@@ -202,13 +207,20 @@ sparse_cases_read (struct sparse_cases *sc, casenumber row, size_t column,
 
   if (sparse_cases_contains_row (sc, row))
     {
-      struct ccase c;
+      struct ccase *c;
       if (sc->memory != NULL)
-        case_clone (&c, sparse_array_get (sc->memory, row));
-      else if (!case_tmpfile_get_case (sc->disk, row, &c))
-        return false;
-      case_copy_out (&c, column, values, value_cnt);
-      case_destroy (&c);
+        {
+          struct ccase **cp = sparse_array_get (sc->memory, row);
+          c = case_ref (*cp);
+        }
+      else
+        {
+          c = case_tmpfile_get_case (sc->disk, row);
+          if (c == NULL)
+            return false;
+        }
+      case_copy_out (c, column, values, value_cnt);
+      case_unref (c);
     }
   else
     {
@@ -225,20 +237,24 @@ static bool
 write_disk_case (struct sparse_cases *sc, casenumber row, size_t column,
                  const union value values[], size_t value_cnt)
 {
-  struct ccase c;
+  struct ccase *c;
   bool ok;
 
   /* Get current case data. */
   if (column == 0 && value_cnt == sc->column_cnt)
-    case_create (&c, sc->column_cnt);
-  else if (!case_tmpfile_get_case (sc->disk, row, &c))
-    return false;
+    c = case_create (sc->column_cnt);
+  else
+    {
+      c = case_tmpfile_get_case (sc->disk, row);
+      if (c == NULL)
+        return false;
+    }
 
   /* Copy in new data. */
-  case_copy_in (&c, column, values, value_cnt);
+  case_copy_in (c, column, values, value_cnt);
 
   /* Write new case. */
-  ok = case_tmpfile_put_case (sc->disk, row, &c);
+  ok = case_tmpfile_put_case (sc->disk, row, c);
   if (ok)
     range_set_insert (sc->disk_cases, row, 1);
 
@@ -255,8 +271,11 @@ sparse_cases_write (struct sparse_cases *sc, casenumber row, size_t column,
 {
   if (sc->memory != NULL)
     {
-      struct ccase *c = sparse_array_get (sc->memory, row);
-      if (c == NULL)
+      struct ccase *c, **cp;
+      cp = sparse_array_get (sc->memory, row);
+      if (cp != NULL)
+        c = *cp = case_unshare (*cp);
+      else
         {
           if (sparse_array_count (sc->memory) >= sc->max_memory_cases)
             {
@@ -265,8 +284,8 @@ sparse_cases_write (struct sparse_cases *sc, casenumber row, size_t column,
               return write_disk_case (sc, row, column, values, value_cnt);
             }
 
-          c = sparse_array_insert (sc->memory, row);
-          case_create (c, sc->column_cnt);
+          cp = sparse_array_insert (sc->memory, row);
+          c = *cp = case_create (sc->column_cnt);
           if (sc->default_columns != NULL
               && (column != 0 || value_cnt != sc->column_cnt))
             case_copy_in (c, 0, sc->default_columns, sc->column_cnt);
@@ -302,12 +321,15 @@ sparse_cases_write_columns (struct sparse_cases *sc, size_t start_column,
   /* Set individual rows. */
   if (sc->memory != NULL)
     {
-      struct ccase *c;
+      struct ccase **cp;
       unsigned long int idx;
 
-      for (c = sparse_array_scan (sc->memory, NULL, &idx); c != NULL;
-           c = sparse_array_scan (sc->memory, &idx, &idx))
-        case_copy_in (c, start_column, values, value_cnt);
+      for (cp = sparse_array_scan (sc->memory, NULL, &idx); cp != NULL;
+           cp = sparse_array_scan (sc->memory, &idx, &idx))
+        {
+          *cp = case_unshare (*cp);
+          case_copy_in (*cp, start_column, values, value_cnt);
+        }
     }
   else
     {
index 3e019c7c8497bf3340bf1dc2cce256fe6d85aad4..d4b137830608374637bed3aeca1cc98083909dc9 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 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
@@ -168,7 +168,9 @@ subcase_inject (const struct subcase *sc,
 /* Copies the fields in SRC represented by SRC_SC into the
    corresponding fields in DST respresented by DST_SC.  SRC_SC
    and DST_SC must be conformable (as tested by
-   subcase_conformable()). */
+   subcase_conformable()).
+
+   DST must not be shared. */
 void
 subcase_copy (const struct subcase *src_sc, const struct ccase *src,
               const struct subcase *dst_sc, struct ccase *dst)
index c80bd5f557246cead2e3cc0feeb743834a48d0f5..af09189e1fa0721919597bb18eef4d1508e07f1d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 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
@@ -1304,24 +1304,24 @@ static bool read_compressed_string (struct sfm_reader *, char *);
 static bool read_whole_strings (struct sfm_reader *, char *, size_t);
 static bool skip_whole_strings (struct sfm_reader *, size_t);
 
-/* Reads one case from READER's file into C.  Returns true only
-   if successful. */
-static bool
-sys_file_casereader_read (struct casereader *reader, void *r_,
-                          struct ccase *c)
+/* Reads and returns one case from READER's file.  Returns a null
+   pointer if not successful. */
+static struct ccase *
+sys_file_casereader_read (struct casereader *reader, void *r_)
 {
   struct sfm_reader *r = r_;
+  struct ccase *volatile c;
   int i;
 
   if (r->error)
-    return false;
+    return NULL;
 
-  case_create (c, r->value_cnt);
+  c = case_create (r->value_cnt);
   if (setjmp (r->bail_out))
     {
       casereader_force_error (reader);
-      case_destroy (c);
-      return false;
+      case_unref (c);
+      return NULL;
     }
 
   for (i = 0; i < r->sfm_var_cnt; i++)
@@ -1342,15 +1342,15 @@ sys_file_casereader_read (struct casereader *reader, void *r_,
             partial_record (r);
         }
     }
-  return true;
+  return c;
 
 eof:
-  case_destroy (c);
+  case_unref (c);
   if (i != 0)
     partial_record (r);
   if (r->case_cnt != -1)
     read_error (reader, r);
-  return false;
+  return NULL;
 }
 
 /* Issues an error that R ends in a partial record. */
index eaf051fed7a6cc73c7e5a82628100d38554ea55d..242857494ee365af5238936bdd8c7e2027c30c0a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -47,7 +47,6 @@ struct sfm_read_info
 
 struct dictionary;
 struct file_handle;
-struct ccase;
 struct casereader *sfm_open_reader (struct file_handle *,
                                     struct dictionary **,
                                     struct sfm_read_info *);
index aa539a51364fb6804aa1ddfc2b14d2ee545ebbc3..393be4e1265292b58fc37daa64bfaf4a4ff40a15 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 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
@@ -126,8 +126,9 @@ static void write_zeros (struct sfm_writer *, size_t);
 static void write_spaces (struct sfm_writer *, size_t);
 static void write_value (struct sfm_writer *, const union value *, int width);
 
-static void write_case_uncompressed (struct sfm_writer *, struct ccase *);
-static void write_case_compressed (struct sfm_writer *, struct ccase *);
+static void write_case_uncompressed (struct sfm_writer *,
+                                     const struct ccase *);
+static void write_case_compressed (struct sfm_writer *, const struct ccase *);
 static void flush_compressed (struct sfm_writer *);
 static void put_cmp_opcode (struct sfm_writer *, uint8_t);
 static void put_cmp_number (struct sfm_writer *, double);
@@ -747,7 +748,7 @@ sys_file_casewriter_write (struct casewriter *writer, void *w_,
   if (ferror (w->file))
     {
       casewriter_force_error (writer);
-      case_destroy (c);
+      case_unref (c);
       return;
     }
 
@@ -758,7 +759,7 @@ sys_file_casewriter_write (struct casewriter *writer, void *w_,
   else
     write_case_compressed (w, c);
 
-  case_destroy (c);
+  case_unref (c);
 }
 
 /* Destroys system file writer W. */
@@ -836,7 +837,7 @@ static const struct casewriter_class sys_file_casewriter_class =
 \f
 /* Writes case C to system file W, without compressing it. */
 static void
-write_case_uncompressed (struct sfm_writer *w, struct ccase *c)
+write_case_uncompressed (struct sfm_writer *w, const struct ccase *c)
 {
   size_t i;
 
@@ -857,7 +858,7 @@ write_case_uncompressed (struct sfm_writer *w, struct ccase *c)
 
 /* Writes case C to system file W, with compression. */
 static void
-write_case_compressed (struct sfm_writer *w, struct ccase *c)
+write_case_compressed (struct sfm_writer *w, const struct ccase *c)
 {
   size_t i;
 
index c6128d45677009a5cff5cff45e249a5cd53c658f..fdff49fe52a165d02488e51d67c0efd758e3047b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -31,7 +31,6 @@ struct sfm_write_options
 
 struct file_handle;
 struct dictionary;
-struct ccase;
 struct casewriter *sfm_open_writer (struct file_handle *, struct dictionary *,
                                     struct sfm_write_options);
 struct sfm_write_options sfm_writer_default_options (void);
index 08b43139e9ff118de981f61808f4bea52ea52d12..2a73cade41bbcf6e4c55622c5d00b9d8b18505b6 100644 (file)
@@ -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
@@ -178,14 +178,15 @@ trns_chain_next (struct trns_chain *chain)
   return chain->trns_cnt;
 }
 
-/* Executes the given CHAIN of transformations on C,
+/* Executes the given CHAIN of transformations on *C,
    passing CASE_NR as the case number.
+   *C may be replaced by a new case.
    Returns the result code that caused the transformations to
    terminate, or TRNS_CONTINUE if the transformations finished
    due to "falling off the end" of the set of transformations. */
 enum trns_result
 trns_chain_execute (const struct trns_chain *chain, enum trns_result start,
-                    struct ccase *c, casenumber case_nr)
+                    struct ccase **c, casenumber case_nr)
 {
   size_t i;
 
index 0a8c53e2c8bc33c571d7e0cffef3fac7d31099a3..59001f1139da18a544775337b9921baa435b7e6c 100644 (file)
@@ -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
@@ -33,7 +33,7 @@ enum trns_result
 
 struct ccase;
 typedef void trns_finalize_func (void *);
-typedef int trns_proc_func (void *, struct ccase *, casenumber);
+typedef int trns_proc_func (void *, struct ccase **, casenumber);
 typedef bool trns_free_func (void *);
 \f
 /* Transformation chains. */
@@ -47,8 +47,9 @@ bool trns_chain_is_empty (const struct trns_chain *);
 void trns_chain_append (struct trns_chain *, trns_finalize_func *,
                         trns_proc_func *, trns_free_func *, void *);
 size_t trns_chain_next (struct trns_chain *);
-enum trns_result trns_chain_execute (const struct trns_chain *, enum trns_result,
-                                     struct ccase *, casenumber case_nr);
+enum trns_result trns_chain_execute (const struct trns_chain *,
+                                     enum trns_result, struct ccase **,
+                                     casenumber case_nr);
 
 void trns_chain_splice (struct trns_chain *, struct trns_chain *);
 
index ccbe65dc0ed9757be75091637bb346b276182d84..30cf03b134666cf8f6db1f457c8e3733b0b311e9 100644 (file)
@@ -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);
 
index a62351630006b508238ddb28b8bea2fb77c878cb..4210b7fce45f8f05153f9fd4bd2cd28881255b01 100644 (file)
@@ -14,7 +14,6 @@ noinst_LTLIBRARIES +=  src/language/liblanguage.la
 
 
 src_language_liblanguage_la_LIBADD = \
-       lib/misc/libmisc.la \
        src/output/charts/libcharts.la
 
 src_language_liblanguage_la_SOURCES = \
index e06261f94cdf89ac17e8c04c6bacff26b885f792..f87747d892e8d9566da798936f243ad0fdd46ec1 100644 (file)
@@ -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")
index 61c450a52359b76683a5c7f9c6ca926801c8c032..b3b6135f6ec4336e26a30e71da855d25c41d1e4f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -240,7 +240,7 @@ do_if_finalize_func (void *do_if_ UNUSED)
    Checks each clause and jumps to the appropriate
    transformation. */
 static int
-do_if_trns_proc (void *do_if_, struct ccase *c, casenumber case_num UNUSED)
+do_if_trns_proc (void *do_if_, struct ccase **c, casenumber case_num UNUSED)
 {
   struct do_if_trns *do_if = do_if_;
   struct clause *clause;
@@ -250,7 +250,7 @@ do_if_trns_proc (void *do_if_, struct ccase *c, casenumber case_num UNUSED)
     {
       if (clause->condition != NULL)
         {
-          double boolean = expr_evaluate_num (clause->condition, c, case_num);
+          double boolean = expr_evaluate_num (clause->condition, *c, case_num);
           if (boolean == 1.0)
             return clause->target_index;
           else if (boolean == SYSMIS)
@@ -279,7 +279,8 @@ do_if_trns_free (void *do_if_)
 
 /* Breaks out of a DO IF construct. */
 static int
-break_trns_proc (void *do_if_, struct ccase *c UNUSED, casenumber case_num UNUSED)
+break_trns_proc (void *do_if_, struct ccase **c UNUSED,
+                 casenumber case_num UNUSED)
 {
   struct do_if_trns *do_if = do_if_;
 
index 40a33c11bbafc451adddb40f9529356ed12c6776..f5d205d4303e864bf2a6203c3f6bc5792bed1657 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -304,21 +304,22 @@ loop_trns_finalize (void *do_if_ UNUSED)
 
 /* Sets up LOOP for the first pass. */
 static int
-loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num)
+loop_trns_proc (void *loop_, struct ccase **c, casenumber case_num)
 {
   struct loop_trns *loop = loop_;
 
   if (loop->index_var != NULL)
     {
       /* Evaluate loop index expressions. */
-      loop->cur = expr_evaluate_num (loop->first_expr, c, case_num);
+      loop->cur = expr_evaluate_num (loop->first_expr, *c, case_num);
       if (loop->by_expr != NULL)
-       loop->by = expr_evaluate_num (loop->by_expr, c, case_num);
-      loop->last = expr_evaluate_num (loop->last_expr, c, case_num);
+       loop->by = expr_evaluate_num (loop->by_expr, *c, case_num);
+      loop->last = expr_evaluate_num (loop->last_expr, *c, case_num);
 
       /* Even if the loop is never entered, set the index
          variable to the initial value. */
-      case_data_rw (c, loop->index_var)->f = loop->cur;
+      *c = case_unshare (*c);
+      case_data_rw (*c, loop->index_var)->f = loop->cur;
 
       /* Throw out pathological cases. */
       if (!isfinite (loop->cur) || !isfinite (loop->by)
@@ -336,7 +337,7 @@ loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num)
 
   /* Check condition. */
   if (loop->loop_condition != NULL
-      && expr_evaluate_num (loop->loop_condition, c, case_num) != 1.0)
+      && expr_evaluate_num (loop->loop_condition, *c, case_num) != 1.0)
     goto zero_pass;
 
   return loop->past_LOOP_index;
@@ -357,12 +358,12 @@ loop_trns_free (void *loop_)
 
 /* Finishes a pass through the loop and starts the next. */
 static int
-end_loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num UNUSED)
+end_loop_trns_proc (void *loop_, struct ccase **c, casenumber case_num UNUSED)
 {
   struct loop_trns *loop = loop_;
 
   if (loop->end_loop_condition != NULL
-      && expr_evaluate_num (loop->end_loop_condition, c, case_num) != 0.0)
+      && expr_evaluate_num (loop->end_loop_condition, *c, case_num) != 0.0)
     goto break_out;
 
   /* MXLOOPS limiter. */
@@ -380,11 +381,12 @@ end_loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num UNUSED)
       if ((loop->by > 0.0 && loop->cur > loop->last)
           || (loop->by < 0.0 && loop->cur < loop->last))
         goto break_out;
-      case_data_rw (c, loop->index_var)->f = loop->cur;
+      *c = case_unshare (*c);
+      case_data_rw (*c, loop->index_var)->f = loop->cur;
     }
 
   if (loop->loop_condition != NULL
-      && expr_evaluate_num (loop->loop_condition, c, case_num) != 1.0)
+      && expr_evaluate_num (loop->loop_condition, *c, case_num) != 1.0)
     goto break_out;
 
   return loop->past_LOOP_index;
@@ -395,7 +397,8 @@ end_loop_trns_proc (void *loop_, struct ccase *c, casenumber case_num UNUSED)
 
 /* Executes BREAK. */
 static int
-break_trns_proc (void *loop_, struct ccase *c UNUSED, casenumber case_num UNUSED)
+break_trns_proc (void *loop_, struct ccase **c UNUSED,
+                 casenumber case_num UNUSED)
 {
   struct loop_trns *loop = loop_;
 
index 1451743dc882e651751cc9b3ccdbc2d1b8f1829e..ccbe7679d15a6331c93c7f4054ac168cae9f3c00 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 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
@@ -72,7 +72,7 @@ struct comb_file
     struct file_handle *handle; /* Input file handle. */
     struct dictionary *dict;   /* Input file dictionary. */
     struct casereader *reader;  /* Input data source. */
-    struct ccase data;          /* The current input case. */
+    struct ccase *data;         /* The current input case. */
     bool is_minimal;            /* Does 'data' have minimum BY values across
                                    all input files? */
     bool is_sorted;             /* Is file presorted on the BY variables? */
@@ -98,8 +98,8 @@ struct comb_proc
        members used. */
     struct variable *first;     /* Variable specified on FIRST (if any). */
     struct variable *last;      /* Variable specified on LAST (if any). */
-    struct ccase buffered_case; /* Case ready for output except that we don't
-                                   know the value for the LAST variable yet. */
+    struct ccase *buffered_case; /* Case ready for output except that we don't
+                                    know the value for the LAST var yet. */
     union value *prev_BY;       /* Values of BY vars in buffered_case. */
   };
 
@@ -165,7 +165,7 @@ combine_files (enum comb_command_type command,
   subcase_init_empty (&proc.by_vars);
   proc.first = NULL;
   proc.last = NULL;
-  case_nullify (&proc.buffered_case);
+  proc.buffered_case = NULL;
   proc.prev_BY = NULL;
 
   dict_set_case_limit (proc.dict, dict_get_case_limit (dataset_dict (ds)));
@@ -198,7 +198,7 @@ combine_files (enum comb_command_type command,
       file->handle = NULL;
       file->dict = NULL;
       file->reader = NULL;
-      case_nullify (&file->data);
+      file->data = NULL;
       file->is_sorted = true;
       file->in_name[0] = '\0';
       file->in_var = NULL;
@@ -444,7 +444,7 @@ combine_files (enum comb_command_type command,
       if (!file->is_sorted)
         file->reader = sort_execute (file->reader, &file->by_vars);
       taint_propagate (casereader_get_taint (file->reader), taint);
-      casereader_read (file->reader, &file->data);
+      file->data = casereader_read (file->reader);
       if (file->type == COMB_FILE)
         case_matcher_add_input (proc.matcher, &file->by_vars,
                                 &file->data, &file->is_minimal);
@@ -605,7 +605,7 @@ close_all_comb_files (struct comb_proc *proc)
       fh_unref (file->handle);
       dict_destroy (file->dict);
       casereader_destroy (file->reader);
-      case_destroy (&file->data);
+      case_unref (file->data);
     }
   free (proc->files);
   proc->files = NULL;
@@ -621,12 +621,12 @@ free_comb_proc (struct comb_proc *proc)
   casewriter_destroy (proc->output);
   case_matcher_destroy (proc->matcher);
   subcase_destroy (&proc->by_vars);
-  case_destroy (&proc->buffered_case);
+  case_unref (proc->buffered_case);
   free (proc->prev_BY);
 }
 \f
 static bool scan_table (struct comb_file *, union value by[]);
-static void create_output_case (const struct comb_proc *, struct ccase *);
+static struct ccase *create_output_case (const struct comb_proc *);
 static void apply_case (const struct comb_file *, struct ccase *);
 static void apply_file_case_and_advance (struct comb_file *, struct ccase *,
                                          union value by[]);
@@ -641,7 +641,6 @@ execute_add_files (struct comb_proc *proc)
 
   while (case_matcher_match (proc->matcher, &by))
     {
-      struct ccase output;
       size_t i;
 
       for (i = 0; i < proc->n_files; i++)
@@ -649,9 +648,9 @@ execute_add_files (struct comb_proc *proc)
           struct comb_file *file = &proc->files[i];
           while (file->is_minimal)
             {
-              create_output_case (proc, &output);
-              apply_file_case_and_advance (file, &output, by);
-              output_case (proc, &output, by);
+              struct ccase *output = create_output_case (proc);
+              apply_file_case_and_advance (file, output, by);
+              output_case (proc, output, by);
             }
         }
     }
@@ -666,25 +665,25 @@ execute_match_files (struct comb_proc *proc)
 
   while (case_matcher_match (proc->matcher, &by))
     {
-      struct ccase output;
+      struct ccase *output;
       size_t i;
 
-      create_output_case (proc, &output);
+      output = create_output_case (proc);
       for (i = proc->n_files; i-- > 0; )
         {
           struct comb_file *file = &proc->files[i];
           if (file->type == COMB_FILE)
             {
               if (file->is_minimal)
-                apply_file_case_and_advance (file, &output, NULL);
+                apply_file_case_and_advance (file, output, NULL);
             }
           else
             {
               if (scan_table (file, by))
-                apply_case (file, &output);
+                apply_case (file, output);
             }
         }
-      output_case (proc, &output, by);
+      output_case (proc, output, by);
     }
   output_buffered_case (proc);
 }
@@ -699,15 +698,15 @@ execute_update (struct comb_proc *proc)
   while (case_matcher_match (proc->matcher, &by))
     {
       struct comb_file *first, *file;
-      struct ccase output;
+      struct ccase *output;
 
       /* Find first nonnull case in array and make an output case
          from it. */
-      create_output_case (proc, &output);
+      output = create_output_case (proc);
       for (first = &proc->files[0]; ; first++)
         if (first->is_minimal)
           break;
-      apply_file_case_and_advance (first, &output, by);
+      apply_file_case_and_advance (first, output, by);
 
       /* Read additional cases and update the output case from
          them.  (Don't update the output case from any duplicate
@@ -716,9 +715,9 @@ execute_update (struct comb_proc *proc)
            file < &proc->files[proc->n_files]; file++)
         {
           while (file->is_minimal)
-            apply_file_case_and_advance (file, &output, by);
+            apply_file_case_and_advance (file, output, by);
         }
-      casewriter_write (proc->output, &output);
+      casewriter_write (proc->output, output);
 
       /* Write duplicate cases in the master file directly to the
          output.  */
@@ -727,9 +726,9 @@ execute_update (struct comb_proc *proc)
           n_duplicates++;
           while (first->is_minimal)
             {
-              create_output_case (proc, &output);
-              apply_file_case_and_advance (first, &output, by);
-              casewriter_write (proc->output, &output);
+              output = create_output_case (proc);
+              apply_file_case_and_advance (first, output, by);
+              casewriter_write (proc->output, output);
             }
         }
     }
@@ -746,13 +745,13 @@ execute_update (struct comb_proc *proc)
 static bool
 scan_table (struct comb_file *file, union value by[])
 {
-  while (!case_is_null (&file->data))
+  while (file->data != NULL)
     {
-      int cmp = subcase_compare_3way_xc (&file->by_vars, by, &file->data);
+      int cmp = subcase_compare_3way_xc (&file->by_vars, by, file->data);
       if (cmp > 0)
         {
-          case_destroy (&file->data);
-          casereader_read (file->reader, &file->data);
+          case_unref (file->data);
+          file->data = casereader_read (file->reader);
         }
       else
         return cmp == 0;
@@ -760,16 +759,17 @@ scan_table (struct comb_file *file, union value by[])
   return false;
 }
 
-/* Creates OUTPUT as an output case for PROC, by initializing each of
-   its values to system-missing or blanks, except that the values
-   of IN variables are set to 0. */
-static void
-create_output_case (const struct comb_proc *proc, struct ccase *output)
+/* Creates and returns an output case for PROC, initializing each
+   of its values to system-missing or blanks, except that the
+   values of IN variables are set to 0. */
+static struct ccase *
+create_output_case (const struct comb_proc *proc)
 {
   size_t n_vars = dict_get_var_cnt (proc->dict);
+  struct ccase *output;
   size_t i;
 
-  case_create (output, dict_get_next_value_idx (proc->dict));
+  output = case_create (dict_get_next_value_idx (proc->dict));
   for (i = 0; i < n_vars; i++)
     {
       struct variable *v = dict_get_var (proc->dict, i);
@@ -781,6 +781,7 @@ create_output_case (const struct comb_proc *proc, struct ccase *output)
       if (file->in_var != NULL)
         case_data_rw (output, file->in_var)->f = false;
     }
+  return output;
 }
 
 /* Copies the data from FILE's case into output case OUTPUT.
@@ -788,7 +789,7 @@ create_output_case (const struct comb_proc *proc, struct ccase *output)
 static void
 apply_case (const struct comb_file *file, struct ccase *output)
 {
-  subcase_copy (&file->src, &file->data, &file->dst, output);
+  subcase_copy (&file->src, file->data, &file->dst, output);
   if (file->in_var != NULL)
     case_data_rw (output, file->in_var)->f = true;
 }
@@ -802,11 +803,11 @@ apply_file_case_and_advance (struct comb_file *file, struct ccase *output,
                              union value by[])
 {
   apply_case (file, output);
-  case_destroy (&file->data);
-  casereader_read (file->reader, &file->data);
+  case_unref (file->data);
+  file->data = casereader_read (file->reader);
   if (by)
-    file->is_minimal = (!case_is_null (&file->data)
-                        && subcase_equal_cx (&file->by_vars, &file->data, by));
+    file->is_minimal = (file->data != NULL
+                        && subcase_equal_cx (&file->by_vars, file->data, by));
 }
 
 /* Writes OUTPUT, whose BY values has been extracted into BY, to
@@ -828,15 +829,15 @@ output_case (struct comb_proc *proc, struct ccase *output, union value by[])
         {
           new_BY = !subcase_equal_xx (&proc->by_vars, proc->prev_BY, by);
           if (proc->last != NULL)
-            case_data_rw (&proc->buffered_case, proc->last)->f = new_BY;
-          casewriter_write (proc->output, &proc->buffered_case);
+            case_data_rw (proc->buffered_case, proc->last)->f = new_BY;
+          casewriter_write (proc->output, proc->buffered_case);
         }
       else
         new_BY = true;
 
-      case_move (&proc->buffered_case, output);
+      proc->buffered_case = output;
       if (proc->first != NULL)
-        case_data_rw (&proc->buffered_case, proc->first)->f = new_BY;
+        case_data_rw (proc->buffered_case, proc->first)->f = new_BY;
 
       if (new_BY)
         {
@@ -857,8 +858,8 @@ output_buffered_case (struct comb_proc *proc)
   if (proc->prev_BY != NULL)
     {
       if (proc->last != NULL)
-        case_data_rw (&proc->buffered_case, proc->last)->f = 1.0;
-      casewriter_write (proc->output, &proc->buffered_case);
-      case_nullify (&proc->buffered_case);
+        case_data_rw (proc->buffered_case, proc->last)->f = 1.0;
+      casewriter_write (proc->output, proc->buffered_case);
+      proc->buffered_case = NULL;
     }
 }
index 7a2a074b59e763eebe322780c96e86f057991ed6..d07eae5c554f7cb19b665175e2a45f9146e08102 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 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
@@ -463,14 +463,15 @@ data_list_trns_free (void *trns_)
   return true;
 }
 
-/* Handle DATA LIST transformation TRNS, parsing data into C. */
+/* Handle DATA LIST transformation TRNS, parsing data into *C. */
 static int
-data_list_trns_proc (void *trns_, struct ccase *c, casenumber case_num UNUSED)
+data_list_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED)
 {
   struct data_list_trns *trns = trns_;
   int retval;
 
-  if (data_parser_parse (trns->parser, trns->reader, c))
+  *c = case_unshare (*c);
+  if (data_parser_parse (trns->parser, trns->reader, *c))
     retval = TRNS_CONTINUE;
   else if (dfm_reader_error (trns->reader) || dfm_eof (trns->reader) > 1)
     {
@@ -484,7 +485,7 @@ data_list_trns_proc (void *trns_, struct ccase *c, casenumber case_num UNUSED)
   /* If there was an END subcommand handle it. */
   if (trns->end != NULL)
     {
-      double *end = &case_data_rw (c, trns->end)->f;
+      double *end = &case_data_rw (*c, trns->end)->f;
       if (retval == TRNS_END_FILE)
         {
           *end = 1.0;
index dfc04be44c52b2cfc5f09a2b2dfc9432018ca10d..87fd1b7919f6de9de5ec076dd1c1dc794840f47f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -364,14 +364,17 @@ static bool parse_delimited_no_span (const struct data_parser *,
 static bool parse_fixed (const struct data_parser *,
                          struct dfm_reader *, struct ccase *);
 
-/* Reads a case from DFM into C, parsing it with PARSER.
-   Returns true if successful, false at end of file or on I/O error. */
+/* Reads a case from DFM into C, parsing it with PARSER.  Returns
+   true if successful, false at end of file or on I/O error.
+
+   Case C must not be shared. */
 bool
 data_parser_parse (struct data_parser *parser, struct dfm_reader *reader,
                    struct ccase *c)
 {
   bool retval;
 
+  assert (!case_is_shared (c));
   assert (data_parser_any_fields (parser));
 
   /* Skip the requested number of records before reading the
@@ -746,18 +749,18 @@ data_parser_make_active_file (struct data_parser *parser, struct dataset *ds,
   proc_set_active_file (ds, casereader, dict);
 }
 
-static bool
-data_parser_casereader_read (struct casereader *reader UNUSED, void *r_,
-                           struct ccase *c)
+static struct ccase *
+data_parser_casereader_read (struct casereader *reader UNUSED, void *r_)
 {
   struct data_parser_casereader *r = r_;
-  bool ok;
-
-  case_create (c, r->value_cnt);
-  ok = data_parser_parse (r->parser, r->reader, c);
-  if (!ok)
-    case_destroy (c);
-  return ok;
+  struct ccase *c = case_create (r->value_cnt);
+  if (data_parser_parse (r->parser, r->reader, c))
+    return c;
+  else
+    {
+      case_unref (c);
+      return NULL;
+    }
 }
 
 static void
index 609c9b2c92bec4b85894b6ab26daca928b0031d9..c2e5dc0f721438a7af412fc936e19cb20a99b1d1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -180,35 +180,34 @@ is_valid_state (enum trns_result state)
           || state >= 0);
 }
 
-/* Reads one case into C.
-   Returns true if successful, false at end of file or if an
+/* Reads and returns one case.
+   Returns the case if successful, null at end of file or if an
    I/O error occurred. */
-static bool
-input_program_casereader_read (struct casereader *reader UNUSED, void *inp_,
-                               struct ccase *c)
+static struct ccase *
+input_program_casereader_read (struct casereader *reader UNUSED, void *inp_)
 {
   struct input_program_pgm *inp = inp_;
-
-  case_create (c, inp->value_cnt);
+  struct ccase *c = case_create (inp->value_cnt);
 
   do
     {
       assert (is_valid_state (inp->restart));
       if (inp->restart == TRNS_ERROR || inp->restart == TRNS_END_FILE)
         {
-          case_destroy (c);
-          return false;
+          case_unref (c);
+          return NULL;
         }
 
+      c = case_unshare (c);
       caseinit_init_vars (inp->init, c);
       inp->restart = trns_chain_execute (inp->trns_chain, inp->restart,
-                                         c, inp->case_nr);
+                                         &c, inp->case_nr);
       assert (is_valid_state (inp->restart));
       caseinit_update_left_vars (inp->init, c);
     }
   while (inp->restart < 0);
 
-  return true;
+  return c;
 }
 
 static void
@@ -251,7 +250,7 @@ cmd_end_case (struct lexer *lexer, struct dataset *ds UNUSED)
 
 /* Outputs the current case */
 int
-end_case_trns_proc (void *inp_, struct ccase *c UNUSED,
+end_case_trns_proc (void *inp_, struct ccase **c UNUSED,
                     casenumber case_nr UNUSED)
 {
   struct input_program_pgm *inp = inp_;
@@ -323,7 +322,7 @@ cmd_reread (struct lexer *lexer, struct dataset *ds)
 
 /* Executes a REREAD transformation. */
 static int
-reread_trns_proc (void *t_, struct ccase *c, casenumber case_num)
+reread_trns_proc (void *t_, struct ccase **c, casenumber case_num)
 {
   struct reread_trns *t = t_;
 
@@ -331,7 +330,7 @@ reread_trns_proc (void *t_, struct ccase *c, casenumber case_num)
     dfm_reread_record (t->reader, 1);
   else
     {
-      double column = expr_evaluate_num (t->column, c, case_num);
+      double column = expr_evaluate_num (t->column, *c, case_num);
       if (!isfinite (column) || column < 1)
        {
          msg (SE, _("REREAD: Column numbers must be positive finite "
@@ -368,7 +367,7 @@ cmd_end_file (struct lexer *lexer, struct dataset *ds)
 
 /* Executes an END FILE transformation. */
 static int
-end_file_trns_proc (void *trns_ UNUSED, struct ccase *c UNUSED,
+end_file_trns_proc (void *trns_ UNUSED, struct ccase **c UNUSED,
                     casenumber case_num UNUSED)
 {
   return TRNS_END_FILE;
index 8e8bba9b69a281ae707cd021d2bd777e0176bf6f..28820a8504b5fdfc15c8ede3338439ab0f1b4d7a 100644 (file)
@@ -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
@@ -83,7 +83,7 @@ static unsigned n_chars_width (struct outp_driver *d);
 static void write_line (struct outp_driver *d, const char *s);
 
 /* Other functions. */
-static void list_case (struct ccase *, casenumber case_idx,
+static void list_case (const struct ccase *, casenumber case_idx,
                        const struct dataset *);
 static void determine_layout (void);
 static void clean_up (void);
@@ -236,15 +236,15 @@ cmd_list (struct lexer *lexer, struct dataset *ds)
        casegrouper_get_next_group (grouper, &group);
        casereader_destroy (group))
     {
-      struct ccase c;
+      struct ccase *c;
 
       write_all_headers (group, ds);
-      for (; casereader_read (group, &c); case_destroy (&c))
+      for (; (c = casereader_read (group)) != NULL; case_unref (c))
         {
           case_idx++;
           if (case_idx >= cmd.first && case_idx <= cmd.last
               && (case_idx - cmd.first) % cmd.step == 0)
-            list_case (&c, case_idx, ds);
+            list_case (c, case_idx, ds);
         }
     }
   ok = casegrouper_destroy (grouper);
@@ -265,12 +265,13 @@ static void
 write_all_headers (struct casereader *input, const struct dataset *ds)
 {
   struct outp_driver *d;
-  struct ccase c;
+  struct ccase *c;
 
-  if (!casereader_peek (input, 0, &c))
+  c = casereader_peek (input, 0);
+  if (c == NULL)
     return;
-  output_split_file_values (ds, &c);
-  case_destroy (&c);
+  output_split_file_values (ds, c);
+  case_unref (c);
 
   for (d = outp_drivers (NULL); d; d = outp_drivers (d))
     {
@@ -649,7 +650,8 @@ determine_layout (void)
 
 /* Writes case C to output. */
 static void
-list_case (struct ccase *c, casenumber case_idx, const struct dataset *ds)
+list_case (const struct ccase *c, casenumber case_idx,
+           const struct dataset *ds)
 {
   struct dictionary *dict = dataset_dict (ds);
   struct outp_driver *d;
index c3a2e09a3d93f6f56de75da1a12346ee2329a8b7..3f73ee25a8de16fb1f1883608e2c6fa8cf25fdba 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 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
@@ -102,7 +102,7 @@ cmd_print_space (struct lexer *lexer, struct dataset *ds)
 
 /* Executes a PRINT SPACE transformation. */
 static int
-print_space_trns_proc (void *t_, struct ccase *c,
+print_space_trns_proc (void *t_, struct ccase **c,
                        casenumber case_num UNUSED)
 {
   struct print_space_trns *trns = t_;
@@ -111,7 +111,7 @@ print_space_trns_proc (void *t_, struct ccase *c,
   n = 1;
   if (trns->expr)
     {
-      double f = expr_evaluate_num (trns->expr, c, case_num);
+      double f = expr_evaluate_num (trns->expr, *c, case_num);
       if (f == SYSMIS)
         msg (SW, _("The expression on PRINT SPACE evaluated to the "
                    "system-missing value."));
index 408224afb921acd9900d53b44a092d1a28302725..ab25ec758d784128a09e15c1ebc336f8d7e24ce8 100644 (file)
@@ -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
@@ -450,7 +450,7 @@ static void flush_records (struct print_trns *, int target_record,
 
 /* Performs the transformation inside print_trns T on case C. */
 static int
-print_trns_proc (void *trns_, struct ccase *c, casenumber case_num UNUSED)
+print_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED)
 {
   struct print_trns *trns = trns_;
   bool eject = trns->eject;
@@ -467,7 +467,7 @@ print_trns_proc (void *trns_, struct ccase *c, casenumber case_num UNUSED)
       ds_set_length (&trns->line, spec->first_column, encoded_space);
       if (spec->type == PRT_VAR)
         {
-          const union value *input = case_data (c, spec->var);
+          const union value *input = case_data (*c, spec->var);
           char *output = ds_put_uninit (&trns->line, spec->format.w);
           if (!spec->sysmis_as_spaces || input->f != SYSMIS)
             data_out_legacy (input, trns->encoding, &spec->format, output);
index e94c020b168d3a59473b396c0c64aa405bcf1877..c34d446225bd250a76687ef736aeed697d7027be 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 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
@@ -326,14 +326,12 @@ parse_write_command (struct lexer *lexer, struct dataset *ds,
   return NULL;
 }
 
-/* Writes case C to the system file specified on XSAVE or XEXPORT. */
+/* Writes case *C to the system file specified on XSAVE or XEXPORT. */
 static int
-output_trns_proc (void *trns_, struct ccase *c, casenumber case_num UNUSED)
+output_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED)
 {
   struct output_trns *t = trns_;
-  struct ccase tmp;
-  case_clone (&tmp, c);
-  casewriter_write (t->writer, &tmp);
+  casewriter_write (t->writer, case_ref (*c));
   return TRNS_CONTINUE;
 }
 
index fc5b74a3ab57b7727e96226c785640e5a3e8ee43..91b9c84249b76c0e7d799ad7dc089f66874c314a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 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
@@ -170,12 +170,9 @@ cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED)
             }
 
           if (c == NULL)
-            {
-              c = xmalloc (sizeof *c);
-              case_create (c, dict_get_next_value_idx (d));
-            }
+            c = case_create (dict_get_next_value_idx (d));
           else
-            case_resize (c, dict_get_next_value_idx (d));
+            c = case_resize (c, dict_get_next_value_idx (d));
 
           if (lex_is_number (lexer))
             case_data_rw (c, v)->f = lex_tokval (lexer);
@@ -255,11 +252,7 @@ cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED)
   if (ds)
     destroy_dataset (ds);
 
-  if (c != NULL)
-    {
-      case_destroy (c);
-      free (c);
-    }
+  case_unref (c);
 
   return retval;
 }
index ea640e18e194a27aa1d99cd6676eb495417186e7..2d31bd47182dcb158d9f9c50e644fb03bb7b07bf 100644 (file)
@@ -1,7 +1,7 @@
 // -*- c -*-
 //
 // PSPP - a program for statistical analysis.
-// Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+// Copyright (C) 2005, 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
@@ -988,7 +988,7 @@ no_opt string operator STR_VAR ()
 no_opt perm_only function LAG (num_var v, pos_int n_before)
     dataset ds;
 {
-  struct ccase *c = lagged_case (ds, n_before);
+  const struct ccase *c = lagged_case (ds, n_before);
   if (c != NULL)
     {
       double x = case_num (c, v);
@@ -1001,7 +1001,7 @@ no_opt perm_only function LAG (num_var v, pos_int n_before)
 no_opt perm_only function LAG (num_var v)
     dataset ds;
 {
-  struct ccase *c = lagged_case (ds, 1);
+  const struct ccase *c = lagged_case (ds, 1);
   if (c != NULL)
     {
       double x = case_num (c, v);
@@ -1015,7 +1015,7 @@ no_opt perm_only string function LAG (str_var v, pos_int n_before)
      expression e;
      dataset ds;
 {
-  struct ccase *c = lagged_case (ds, n_before);
+  const struct ccase *c = lagged_case (ds, n_before);
   if (c != NULL)
     return copy_string (e, case_str (c, v), var_get_width (v));
   else
@@ -1026,7 +1026,7 @@ no_opt perm_only string function LAG (str_var v)
      expression e;
      dataset ds;
 {
-  struct ccase *c = lagged_case (ds, 1);
+  const struct ccase *c = lagged_case (ds, 1);
   if (c != NULL)
     return copy_string (e, case_str (c, v), var_get_width (v));
   else
index cc8cab808948973b08e9145f337edf8028afb70b..16195b0dd22303a92f5c3075488f58ec8da5d088 100644 (file)
@@ -17,7 +17,8 @@
 #include <config.h>
 #include "lexer.h"
 #include <libpspp/message.h>
-#include <ctype.h>
+#include <c-ctype.h>
+#include <c-strtod.h>
 #include <errno.h>
 #include <limits.h>
 #include <math.h>
@@ -187,7 +188,7 @@ lex_get (struct lexer *lexer)
   for (;;)
     {
       /* Skip whitespace. */
-         while (isspace ((unsigned char) *lexer->prog))
+         while (c_isspace ((unsigned char) *lexer->prog))
            lexer->prog++;
 
          if (*lexer->prog)
@@ -244,10 +245,10 @@ lex_get (struct lexer *lexer)
            if (*lexer->prog == '-')
              {
                ds_put_char (&lexer->tokstr, *lexer->prog++);
-               while (isspace ((unsigned char) *lexer->prog))
+               while (c_isspace ((unsigned char) *lexer->prog))
                  lexer->prog++;
 
-               if (!isdigit ((unsigned char) *lexer->prog) && *lexer->prog != '.')
+               if (!c_isdigit ((unsigned char) *lexer->prog) && *lexer->prog != '.')
                  {
                    lexer->token = '-';
                    break;
@@ -258,12 +259,12 @@ lex_get (struct lexer *lexer)
               lexer->token = T_POS_NUM;
 
            /* Parse the number, copying it into tokstr. */
-           while (isdigit ((unsigned char) *lexer->prog))
+           while (c_isdigit ((unsigned char) *lexer->prog))
              ds_put_char (&lexer->tokstr, *lexer->prog++);
            if (*lexer->prog == '.')
              {
                ds_put_char (&lexer->tokstr, *lexer->prog++);
-               while (isdigit ((unsigned char) *lexer->prog))
+               while (c_isdigit ((unsigned char) *lexer->prog))
                  ds_put_char (&lexer->tokstr, *lexer->prog++);
              }
            if (*lexer->prog == 'e' || *lexer->prog == 'E')
@@ -271,12 +272,12 @@ lex_get (struct lexer *lexer)
                ds_put_char (&lexer->tokstr, *lexer->prog++);
                if (*lexer->prog == '+' || *lexer->prog == '-')
                  ds_put_char (&lexer->tokstr, *lexer->prog++);
-               while (isdigit ((unsigned char) *lexer->prog))
+               while (c_isdigit ((unsigned char) *lexer->prog))
                  ds_put_char (&lexer->tokstr, *lexer->prog++);
              }
 
            /* Parse as floating point. */
-           lexer->tokval = strtod (ds_cstr (&lexer->tokstr), &tail);
+           lexer->tokval = c_strtod (ds_cstr (&lexer->tokstr), &tail);
            if (*tail)
              {
                msg (SE, _("%s does not form a valid number."),
@@ -383,7 +384,7 @@ lex_get (struct lexer *lexer)
             }
           else
             {
-              if (isgraph ((unsigned char) *lexer->prog))
+              if (c_isgraph ((unsigned char) *lexer->prog))
                 msg (SE, _("Bad character in input: `%c'."), *lexer->prog++);
               else
                 msg (SE, _("Bad character in input: `\\%o'."), *lexer->prog++);
@@ -691,7 +692,7 @@ lex_look_ahead (struct lexer *lexer)
 
       for (;;)
        {
-         while (isspace ((unsigned char) *lexer->prog))
+         while (c_isspace ((unsigned char) *lexer->prog))
            lexer->prog++;
          if (*lexer->prog)
            break;
@@ -866,7 +867,7 @@ lex_preprocess_line (struct string *line,
   if (syntax == GETL_BATCH)
     {
       int first = ds_first (line);
-      *line_starts_command = !isspace (first);
+      *line_starts_command = !c_isspace (first);
       if (first == '+' || first == '-')
         *ds_data (line) = ' ';
     }
@@ -951,7 +952,7 @@ lex_token_representation (struct lexer *lexer)
        char *sp, *dp;
 
        for (sp = ds_cstr (&lexer->tokstr); sp < ds_end (&lexer->tokstr); sp++)
-         if (!isprint ((unsigned char) *sp))
+         if (!c_isprint ((unsigned char) *sp))
            {
              hexstring = 1;
              break;
@@ -1165,7 +1166,7 @@ parse_string (struct lexer *lexer, enum string_type type)
        break;
       for (;;)
        {
-         while (isspace ((unsigned char) *lexer->prog))
+         while (c_isspace ((unsigned char) *lexer->prog))
            lexer->prog++;
          if (*lexer->prog)
            break;
@@ -1187,7 +1188,7 @@ parse_string (struct lexer *lexer, enum string_type type)
        break;
       for (;;)
        {
-         while (isspace ((unsigned char) *lexer->prog))
+         while (c_isspace ((unsigned char) *lexer->prog))
            lexer->prog++;
          if (*lexer->prog)
            break;
index 02257f9434f29555bcb2538f5b321a961d099788..c217310910271f2639830eb09d44b2fcdffd69db 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2008 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2008, 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
@@ -146,7 +146,7 @@ struct agr_proc
     struct subcase sort;                /* Sort criteria (break variables). */
     const struct variable **break_vars;       /* Break variables. */
     size_t break_var_cnt;               /* Number of break variables. */
-    struct ccase break_case;            /* Last values of break variables. */
+    struct ccase *break_case;           /* Last values of break variables. */
 
     enum missing_treatment missing;     /* How to treat missing values. */
     struct agr_var *agr_vars;           /* First aggregate variable. */
@@ -187,7 +187,7 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds)
 
   memset(&agr, 0 , sizeof (agr));
   agr.missing = ITEMWISE;
-  case_nullify (&agr.break_case);
+  agr.break_case = NULL;
 
   agr.dict = dict_create ();
   agr.src_dict = dict;
@@ -295,18 +295,17 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds)
        casegrouper_get_next_group (grouper, &group);
        casereader_destroy (group))
     {
-      struct ccase c;
-
-      if (!casereader_peek (group, 0, &c))
+      struct ccase *c = casereader_peek (group, 0);
+      if (c == NULL)
         {
           casereader_destroy (group);
           continue;
         }
-      initialize_aggregate_info (&agr, &c);
-      case_destroy (&c);
+      initialize_aggregate_info (&agr, c);
+      case_unref (c);
 
-      for (; casereader_read (group, &c); case_destroy (&c))
-        accumulate_aggregate_info (&agr, &c);
+      for (; (c = casereader_read (group)) != NULL; case_unref (c))
+        accumulate_aggregate_info (&agr, c);
       dump_aggregate_info (&agr, output);
     }
   if (!casegrouper_destroy (grouper))
@@ -694,7 +693,7 @@ agr_destroy (struct agr_proc *agr)
 
   subcase_destroy (&agr->sort);
   free (agr->break_vars);
-  case_destroy (&agr->break_case);
+  case_unref (agr->break_case);
   for (iter = agr->agr_vars; iter; iter = next)
     {
       next = iter->next;
@@ -770,20 +769,18 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input)
          case MEDIAN:
            {
              double wv ;
-             struct ccase cout;
-             case_create (&cout, 2);
+             struct ccase *cout = case_create (2);
 
-             case_data_rw (&cout, iter->subject)->f =
-               case_data (input, iter->src)->f;
+             case_data_rw (cout, iter->subject)->f
+                = case_data (input, iter->src)->f;
 
              wv = dict_get_case_weight (agr->src_dict, input, NULL);
 
-             case_data_rw (&cout, iter->weight)->f = wv;
+             case_data_rw (cout, iter->weight)->f = wv;
 
              iter->cc += wv;
 
-             casewriter_write (iter->writer, &cout);
-             case_destroy (&cout);
+             casewriter_write (iter->writer, cout);
            }
            break;
          case SD:
@@ -916,9 +913,7 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input)
 static void
 dump_aggregate_info (struct agr_proc *agr, struct casewriter *output)
 {
-  struct ccase c;
-
-  case_create (&c, dict_get_next_value_idx (agr->dict));
+  struct ccase *c = case_create (dict_get_next_value_idx (agr->dict));
 
   {
     int value_idx = 0;
@@ -928,8 +923,8 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output)
       {
         const struct variable *v = agr->break_vars[i];
         size_t value_cnt = var_get_value_cnt (v);
-        memcpy (case_data_rw_idx (&c, value_idx),
-                case_data (&agr->break_case, v),
+        memcpy (case_data_rw_idx (c, value_idx),
+                case_data (agr->break_case, v),
                 sizeof (union value) * value_cnt);
         value_idx += value_cnt;
       }
@@ -940,7 +935,7 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output)
 
     for (i = agr->agr_vars; i; i = i->next)
       {
-       union value *v = case_data_rw (&c, i->dest);
+       union value *v = case_data_rw (c, i->dest);
 
 
        if (agr->missing == COLUMNWISE && i->saw_missing
@@ -1067,7 +1062,7 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output)
       }
   }
 
-  casewriter_write (output, &c);
+  casewriter_write (output, c);
 }
 
 /* Resets the state for all the aggregate functions. */
@@ -1076,8 +1071,8 @@ initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input)
 {
   struct agr_var *iter;
 
-  case_destroy (&agr->break_case);
-  case_clone (&agr->break_case, input);
+  case_unref (agr->break_case);
+  agr->break_case = case_ref (input);
 
   for (iter = agr->agr_vars; iter; iter = iter->next)
     {
index af9280b557c5669e4ec0033de09b8c17ca4c2e9d..de9416821c15bf5fa8c37d5e9a241d7a647fd804 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -103,7 +103,7 @@ cmd_autorecode (struct lexer *lexer, struct dataset *ds)
 {
   struct autorecode_pgm arc;
   struct casereader *input;
-  struct ccase c;
+  struct ccase *c;
   size_t dst_cnt;
   size_t i;
   bool ok;
@@ -189,15 +189,15 @@ cmd_autorecode (struct lexer *lexer, struct dataset *ds)
    }
 
   input = proc_open (ds);
-  for (; casereader_read (input, &c); case_destroy (&c))
+  for (; (c = casereader_read (input)) != NULL; case_unref (c))
     for (i = 0; i < arc.var_cnt; i++)
       {
         union arc_value v, *vp, **vpp;
 
         if (var_is_numeric (arc.src_vars[i]))
-          v.f = case_num (&c, arc.src_vars[i]);
+          v.f = case_num (c, arc.src_vars[i]);
         else
-          v.c = (char *) case_str (&c, arc.src_vars[i]);
+          v.c = (char *) case_str (c, arc.src_vars[i]);
 
         vpp = (union arc_value **) hsh_probe (arc.src_values[i], &v);
         if (*vpp == NULL)
@@ -300,11 +300,13 @@ recode (struct dataset *ds, const struct autorecode_pgm *arc)
 
 /* Executes an AUTORECODE transformation. */
 static int
-autorecode_trns_proc (void *trns_, struct ccase *c, casenumber case_idx UNUSED)
+autorecode_trns_proc (void *trns_, struct ccase **c,
+                      casenumber case_idx UNUSED)
 {
   struct autorecode_trns *trns = trns_;
   size_t i;
 
+  *c = case_unshare (*c);
   for (i = 0; i < trns->spec_cnt; i++)
     {
       struct arc_spec *spec = &trns->specs[i];
@@ -312,12 +314,12 @@ autorecode_trns_proc (void *trns_, struct ccase *c, casenumber case_idx UNUSED)
       union arc_value v;
 
       if (var_is_numeric (spec->src))
-        v.f = case_num (c, spec->src);
+        v.f = case_num (*c, spec->src);
       else
-        v.c = (char *) case_str (c, spec->src);
+        v.c = (char *) case_str (*c, spec->src);
       item = hsh_force_find (spec->items, &v);
 
-      case_data_rw (c, spec->dest)->f = item->to;
+      case_data_rw (*c, spec->dest)->f = item->to;
     }
   return TRNS_CONTINUE;
 }
index 35e619bdeeada375af47915199d0c5addcfb2708..b62b4dce1375a11c11030ca299de2284141261b9 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 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
@@ -98,21 +98,21 @@ do_binomial (const struct dictionary *dict,
   bool warn = true;
 
   const struct one_sample_test *ost = (const struct one_sample_test *) bst;
-  struct ccase c;
+  struct ccase *c;
 
-  while (casereader_read(input, &c))
+  while ((c = casereader_read(input)) != NULL)
     {
       int v;
-      double w = dict_get_case_weight (dict, &c, &warn);
+      double w = dict_get_case_weight (dict, c, &warn);
 
       for (v = 0 ; v < ost->n_vars ; ++v )
        {
          const struct variable *var = ost->vars[v];
-         const union value *value = case_data (&c, var);
+         const union value *value = case_data (c, var);
           int width = var_get_width (var);
 
          if (var_is_value_missing (var, value, exclude))
-           break;
+           continue;
 
          if ( NULL == cat1[v].value )
            {
@@ -132,7 +132,7 @@ do_binomial (const struct dictionary *dict,
            msg (ME, _("Variable %s is not dichotomous"), var_get_name (var));
        }
 
-      case_destroy (&c);
+      case_unref (c);
     }
   return casereader_destroy (input);
 }
@@ -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))
index ed143824187593f984324bc39afeaf810c0080df..19496d7ead9016de96949f5502abfdc6f7576eea 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2007, 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
@@ -57,7 +57,7 @@ create_freq_hash_with_range (const struct dictionary *dict,
 {
   bool warn = true;
   float i_d;
-  struct ccase c;
+  struct ccase *c;
 
   struct hsh_table *freq_hash =
     hsh_create (4, compare_freq, hash_freq,
@@ -78,21 +78,21 @@ create_freq_hash_with_range (const struct dictionary *dict,
       hsh_insert (freq_hash, fr);
     }
 
-  while (casereader_read (input, &c))
+  while ((c = casereader_read (input)) != NULL)
     {
       union value obs_value;
       struct freq **existing_fr;
       struct freq *fr = xmalloc(sizeof  (*fr));
-      fr->value = case_data (&c, var);
+      fr->value = case_data (c, var);
 
-      fr->count = dict_get_case_weight (dict, &c, &warn);
+      fr->count = dict_get_case_weight (dict, c, &warn);
 
       obs_value.f = trunc (fr->value->f);
 
       if ( obs_value.f < lo || obs_value.f > hi)
        {
          free (fr);
-         case_destroy (&c);
+         case_unref (c);
          continue;
        }
 
@@ -107,7 +107,7 @@ create_freq_hash_with_range (const struct dictionary *dict,
       (*existing_fr)->count += fr->count;
       free (fr);
 
-      case_destroy (&c);
+      case_unref (c);
     }
   if (casereader_destroy (input))
     return freq_hash;
@@ -130,20 +130,20 @@ create_freq_hash (const struct dictionary *dict,
                  const struct variable *var)
 {
   bool warn = true;
-  struct ccase c;
+  struct ccase *c;
 
   struct hsh_table *freq_hash =
     hsh_create (4, compare_freq, hash_freq,
                free_freq_mutable_hash,
                (void *) var);
 
-  for (; casereader_read (input, &c); case_destroy (&c))
+  for (; (c = casereader_read (input)) != NULL; case_unref (c))
     {
       struct freq **existing_fr;
       struct freq *fr = xmalloc(sizeof  (*fr));
-      fr->value = case_data (&c, var);
+      fr->value = case_data (c, var);
 
-      fr->count = dict_get_case_weight (dict, &c, &warn);
+      fr->count = dict_get_case_weight (dict, c, &warn);
 
       existing_fr = (struct freq **) hsh_probe (freq_hash, fr);
       if ( *existing_fr)
index 801b128b8a4ad1c5e0398caa897a4cee0a869f08..68d11e307e0ff41584d1ffae0ef4abd6d8c9ff74 100644 (file)
@@ -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
@@ -177,8 +177,8 @@ static struct pool *pl_col; /* For column data. */
 
 static int internal_cmd_crosstabs (struct lexer *lexer, struct dataset *ds);
 static void precalc (struct casereader *, const struct dataset *);
-static void calc_general (struct ccase *, const struct dataset *);
-static void calc_integer (struct ccase *, const struct dataset *);
+static void calc_general (const struct ccase *, const struct dataset *);
+static void calc_integer (const struct ccase *, const struct dataset *);
 static void postcalc (void);
 static void submit (struct tab_table *);
 
@@ -305,16 +305,16 @@ internal_cmd_crosstabs (struct lexer *lexer, struct dataset *ds)
   grouper = casegrouper_create_splits (input, dataset_dict (ds));
   while (casegrouper_get_next_group (grouper, &group))
     {
-      struct ccase c;
+      struct ccase *c;
 
       precalc (group, ds);
 
-      for (; casereader_read (group, &c); case_destroy (&c))
+      for (; (c = casereader_read (group)) != NULL; case_unref (c))
         {
           if (mode == GENERAL)
-            calc_general (&c, ds);
+            calc_general (c, ds);
           else
-            calc_integer (&c, ds);
+            calc_integer (c, ds);
         }
       casereader_destroy (group);
 
@@ -518,12 +518,13 @@ static unsigned hash_table_entry (const void *, const void *);
 static void
 precalc (struct casereader *input, const struct dataset *ds)
 {
-  struct ccase c;
+  struct ccase *c;
 
-  if (casereader_peek (input, 0, &c))
+  c = casereader_peek (input, 0);
+  if (c != NULL)
     {
-      output_split_file_values (ds, &c);
-      case_destroy (&c);
+      output_split_file_values (ds, c);
+      case_unref (c);
     }
 
   if (mode == GENERAL)
@@ -598,7 +599,7 @@ precalc (struct casereader *input, const struct dataset *ds)
 
 /* Form crosstabulations for general mode. */
 static void
-calc_general (struct ccase *c, const struct dataset *ds)
+calc_general (const struct ccase *c, const struct dataset *ds)
 {
   /* Missing values to exclude. */
   enum mv_class exclude = (cmd.miss == CRS_TABLE ? MV_ANY
@@ -672,7 +673,7 @@ calc_general (struct ccase *c, const struct dataset *ds)
 }
 
 static void
-calc_integer (struct ccase *c, const struct dataset *ds)
+calc_integer (const struct ccase *c, const struct dataset *ds)
 {
   bool bad_warn = true;
 
@@ -1674,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);
index 72f7476ae4e89fbc42c6ebe340c134b9b0353b2d..68b19300f6921f80410b7cef01ebe51ab2239876 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -583,7 +583,7 @@ dump_z_table (struct dsc_proc *dsc)
    (either system or user-missing values that weren't included).
 */
 static int
-descriptives_trns_proc (void *trns_, struct ccase * c,
+descriptives_trns_proc (void *trns_, struct ccase **c,
                         casenumber case_idx UNUSED)
 {
   struct dsc_trns *t = trns_;
@@ -596,7 +596,7 @@ descriptives_trns_proc (void *trns_, struct ccase * c,
       assert(t->vars);
       for (vars = t->vars; vars < t->vars + t->var_cnt; vars++)
        {
-         double score = case_num (c, *vars);
+         double score = case_num (*c, *vars);
          if (var_is_num_missing (*vars, score, t->exclude))
            {
              all_sysmis = 1;
@@ -605,10 +605,11 @@ descriptives_trns_proc (void *trns_, struct ccase * c,
        }
     }
 
+  *c = case_unshare (*c);
   for (z = t->z_scores; z < t->z_scores + t->z_score_cnt; z++)
     {
-      double input = case_num (c, z->src_var);
-      double *output = &case_data_rw (c, z->z_var)->f;
+      double input = case_num (*c, z->src_var);
+      double *output = &case_data_rw (*c, z->z_var)->f;
 
       if (z->mean == SYSMIS || z->std_dev == SYSMIS || all_sysmis
           || var_is_num_missing (z->src_var, input, t->exclude))
@@ -695,16 +696,17 @@ calc_descriptives (struct dsc_proc *dsc, struct casereader *group,
                    struct dataset *ds)
 {
   struct casereader *pass1, *pass2;
-  struct ccase c;
+  struct ccase *c;
   size_t i;
 
-  if (!casereader_peek (group, 0, &c))
+  c = casereader_peek (group, 0);
+  if (c == NULL)
     {
       casereader_destroy (group);
       return;
     }
-  output_split_file_values (ds, &c);
-  case_destroy (&c);
+  output_split_file_values (ds, c);
+  case_unref (c);
 
   group = casereader_create_filter_weight (group, dataset_dict (ds),
                                            NULL, NULL);
@@ -726,12 +728,12 @@ calc_descriptives (struct dsc_proc *dsc, struct casereader *group,
   dsc->valid = 0.;
 
   /* First pass to handle most of the work. */
-  for (; casereader_read (pass1, &c); case_destroy (&c))
+  for (; (c = casereader_read (pass1)) != NULL; case_unref (c))
     {
-      double weight = dict_get_case_weight (dataset_dict (ds), &c, NULL);
+      double weight = dict_get_case_weight (dataset_dict (ds), c, NULL);
 
       /* Check for missing values. */
-      if (listwise_missing (dsc, &c))
+      if (listwise_missing (dsc, c))
         {
           dsc->missing_listwise += weight;
           if (dsc->missing_type == DSC_LISTWISE)
@@ -742,7 +744,7 @@ calc_descriptives (struct dsc_proc *dsc, struct casereader *group,
       for (i = 0; i < dsc->var_cnt; i++)
         {
           struct dsc_var *dv = &dsc->vars[i];
-          double x = case_num (&c, dv->v);
+          double x = case_num (c, dv->v);
 
           if (var_is_num_missing (dv->v, x, dsc->exclude))
             {
@@ -768,18 +770,18 @@ calc_descriptives (struct dsc_proc *dsc, struct casereader *group,
   /* Second pass for higher-order moments. */
   if (dsc->max_moment > MOMENT_MEAN)
     {
-      for (; casereader_read (pass2, &c); case_destroy (&c))
+      for (; (c = casereader_read (pass2)) != NULL; case_unref (c))
         {
-          double weight = dict_get_case_weight (dataset_dict (ds), &c, NULL);
+          double weight = dict_get_case_weight (dataset_dict (ds), c, NULL);
 
           /* Check for missing values. */
-          if (dsc->missing_type == DSC_LISTWISE && listwise_missing (dsc, &c))
+          if (dsc->missing_type == DSC_LISTWISE && listwise_missing (dsc, c))
             continue;
 
           for (i = 0; i < dsc->var_cnt; i++)
             {
               struct dsc_var *dv = &dsc->vars[i];
-              double x = case_num (&c, dv->v);
+              double x = case_num (c, dv->v);
 
               if (var_is_num_missing (dv->v, x, dsc->exclude))
                 continue;
index 312547f3f67132380f33d9a204d7049cfb1a670f..78ea0e63c0b1989f3f35a0a1e1105e5bb269f76d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2008, 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
@@ -122,6 +122,9 @@ struct factor_metrics
   /* Sum of all weights, including those for missing values */
   double n;
 
+  /* Sum of weights of non_missing values */
+  double n_valid;
+
   double mean;
 
   double variance;
@@ -369,14 +372,14 @@ np_plot (struct np *np, const char *label)
   chart_write_yscale (dnp_chart, np->dns_min, np->dns_max, 5);
 
   {
-    struct ccase c;
     struct casereader *reader = casewriter_make_reader (np->writer);
-    while (casereader_read (reader, &c))
+    struct ccase *c;
+    while ((c = casereader_read (reader)) != NULL)
       {
-       chart_datum (np_chart, 0, case_data_idx (&c, NP_IDX_Y)->f, case_data_idx (&c, NP_IDX_NS)->f);
-       chart_datum (dnp_chart, 0, case_data_idx (&c, NP_IDX_Y)->f, case_data_idx (&c, NP_IDX_DNS)->f);
+       chart_datum (np_chart, 0, case_data_idx (c, NP_IDX_Y)->f, case_data_idx (c, NP_IDX_NS)->f);
+       chart_datum (dnp_chart, 0, case_data_idx (c, NP_IDX_Y)->f, case_data_idx (c, NP_IDX_DNS)->f);
 
-       case_destroy (&c);
+       case_unref (c);
       }
     casereader_destroy (reader);
   }
@@ -866,7 +869,7 @@ static void
 examine_group (struct cmd_examine *cmd, struct casereader *reader, int level,
               const struct dictionary *dict, struct xfactor *factor)
 {
-  struct ccase c;
+  struct ccase *c;
   const struct variable *wv = dict_get_weight (dict);
   int v;
   int n_extrema = 1;
@@ -878,20 +881,21 @@ examine_group (struct cmd_examine *cmd, struct casereader *reader, int level,
     n_extrema = cmd->st_n;
 
 
-  if (casereader_peek (reader, 0, &c))
+  c = casereader_peek (reader, 0);
+  if (c != NULL)
     {
       if ( level > 0)
        {
          result->value[0] =
-           value_dup (case_data (&c, factor->indep_var[0]),
+           value_dup (case_data (c, factor->indep_var[0]),
                       var_get_width (factor->indep_var[0]));
 
          if ( level > 1)
            result->value[1] =
-             value_dup (case_data (&c, factor->indep_var[1]),
+             value_dup (case_data (c, factor->indep_var[1]),
                         var_get_width (factor->indep_var[1]));
        }
-      case_destroy (&c);
+      case_unref (c);
     }
 
   for (v = 0; v < n_dependent_vars; ++v)
@@ -927,33 +931,37 @@ examine_group (struct cmd_examine *cmd, struct casereader *reader, int level,
 
 
       /* Sort or just iterate, whilst calculating moments etc */
-      while (casereader_read (input, &c))
+      while ((c = casereader_read (input)) != NULL)
        {
          const casenumber loc =
-             case_data_idx (&c, casereader_get_value_cnt (reader) - 1)->f;
+             case_data_idx (c, casereader_get_value_cnt (reader) - 1)->f;
 
-         const double weight = wv ? case_data (&c, wv)->f : 1.0;
+         const double weight = wv ? case_data (c, wv)->f : 1.0;
+         const union value *value = case_data (c, dependent_vars[v]);
 
          if (weight != SYSMIS)
            minimize (&result->metrics[v].cmin, weight);
 
          moments1_add (result->metrics[v].moments,
-                       case_data (&c, dependent_vars[v])->f,
+                       value->f,
                        weight);
 
          result->metrics[v].n += weight;
 
+         if ( ! var_is_value_missing (dependent_vars[v], value, MV_ANY) )
+           result->metrics[v].n_valid += weight;
+
          extrema_add (result->metrics[v].maxima,
-                      case_data (&c, dependent_vars[v])->f,
+                      value->f,
                       weight,
                       loc);
 
          extrema_add (result->metrics[v].minima,
-                      case_data (&c, dependent_vars[v])->f,
+                      value->f,
                       weight,
                       loc);
 
-         casewriter_write (writer, &c);
+         casewriter_write (writer, c);
        }
       casereader_destroy (input);
       result->metrics[v].up_reader = casewriter_make_reader (writer);
@@ -984,7 +992,7 @@ examine_group (struct cmd_examine *cmd, struct casereader *reader, int level,
          for (i = 0 ; i < metric->n_ptiles; ++i)
            {
              metric->ptl[i] = (struct percentile *)
-               percentile_create (percentile_list.data[i] / 100.0, metric->n);
+               percentile_create (percentile_list.data[i] / 100.0, metric->n_valid);
 
              if ( percentile_list.data[i] == 25)
                metric->quartiles[0] = metric->ptl[i];
@@ -1028,7 +1036,7 @@ examine_group (struct cmd_examine *cmd, struct casereader *reader, int level,
   /* FIXME: Do this in the above loop */
   if ( cmd->a_plot[XMN_PLT_HISTOGRAM] )
     {
-      struct ccase c;
+      struct ccase *c;
       struct casereader *input = casereader_clone (reader);
 
       for (v = 0; v < n_dependent_vars; ++v)
@@ -1059,18 +1067,18 @@ examine_group (struct cmd_examine *cmd, struct casereader *reader, int level,
          metric->histogram = histogram_create (10, min->value, max->value);
        }
 
-      while (casereader_read (input, &c))
+      while ((c = casereader_read (input)) != NULL)
        {
-         const double weight = wv ? case_data (&c, wv)->f : 1.0;
+         const double weight = wv ? case_data (c, wv)->f : 1.0;
 
          for (v = 0; v < n_dependent_vars; ++v)
            {
              struct factor_metrics *metric = &result->metrics[v];
              if ( metric->histogram)
                histogram_add ((struct histogram *) metric->histogram,
-                              case_data (&c, dependent_vars[v])->f, weight);
+                              case_data (c, dependent_vars[v])->f, weight);
            }
-         case_destroy (&c);
+         case_unref (c);
        }
       casereader_destroy (input);
     }
@@ -1106,17 +1114,18 @@ run_examine (struct cmd_examine *cmd, struct casereader *input,
 {
   struct ll *ll;
   const struct dictionary *dict = dataset_dict (ds);
-  struct ccase c;
+  struct ccase *c;
   struct casereader *level0 = casereader_clone (input);
 
-  if (!casereader_peek (input, 0, &c))
+  c = casereader_peek (input, 0);
+  if (c == NULL)
     {
       casereader_destroy (input);
       return;
     }
 
-  output_split_file_values (ds, &c);
-  case_destroy (&c);
+  output_split_file_values (ds, c);
+  case_unref (c);
 
   ll_init (&level0_factor.result_list);
 
index ccb84dd8a4f37abecb352a2bf04dc92f95b71602..7583374b22874c530f3047d0adafca477f391247 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -88,7 +88,7 @@ cmd_flip (struct lexer *lexer, struct dataset *ds)
   struct flip_pgm *flip;
   struct casereader *input, *reader;
   union value *output_buf;
-  struct ccase c;
+  struct ccase *c;
   size_t i;
   bool ok;
 
@@ -169,10 +169,10 @@ cmd_flip (struct lexer *lexer, struct dataset *ds)
   proc_discard_output (ds);
 
   input = proc_open (ds);
-  while (casereader_read (input, &c))
+  while ((c = casereader_read (input)) != NULL)
     {
-      write_flip_case (flip, &c);
-      case_destroy (&c);
+      write_flip_case (flip, c);
+      case_unref (c);
     }
   ok = casereader_destroy (input);
   ok = proc_commit (ds) && ok;
@@ -464,26 +464,25 @@ flip_file (struct flip_pgm *flip)
   return true;
 }
 
-/* Reads one case into C.
-   Returns true if successful, false at end of file or if an
-   I/O error occurred. */
-static bool
-flip_casereader_read (struct casereader *reader UNUSED, void *flip_,
-                      struct ccase *c)
+/* Reads and returns one case.
+   Returns a null pointer at end of file or if an I/O error occurred. */
+static struct ccase *
+flip_casereader_read (struct casereader *reader UNUSED, void *flip_)
 {
   struct flip_pgm *flip = flip_;
+  struct ccase *c;
   size_t i;
 
   if (flip->error || flip->cases_read >= flip->var_cnt)
-    return false;
+    return NULL;
 
-  case_create (c, flip->case_cnt);
+  c = case_create (flip->case_cnt);
   for (i = 0; i < flip->case_cnt; i++)
     {
       double in;
       if (fread (&in, sizeof in, 1, flip->file) != 1)
         {
-          case_destroy (c);
+          case_unref (c);
           if (ferror (flip->file))
             msg (SE, _("Error reading FLIP temporary file: %s."),
                  strerror (errno));
@@ -492,14 +491,14 @@ flip_casereader_read (struct casereader *reader UNUSED, void *flip_,
           else
             NOT_REACHED ();
           flip->error = true;
-          return false;
+          return NULL;
         }
       case_data_rw_idx (c, i)->f = in;
     }
 
   flip->cases_read++;
 
-  return true;
+  return c;
 }
 
 /* Destroys the source.
index 94b2bcf9e6edd2303632342d6fa8e80304c62018..cd370be821c8db73f2d88da8350613a7ea8c07b0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2007, 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
@@ -376,11 +376,11 @@ internal_cmd_frequencies (struct lexer *lexer, struct dataset *ds)
   for (; casegrouper_get_next_group (grouper, &group);
        casereader_destroy (group))
     {
-      struct ccase c;
+      struct ccase *c;
 
       precalc (group, ds);
-      for (; casereader_read (group, &c); case_destroy (&c))
-        calc (&c, ds);
+      for (; (c = casereader_read (group)) != NULL; case_unref (c))
+        calc (c, ds);
       postcalc ();
     }
   ok = casegrouper_destroy (grouper);
@@ -535,13 +535,14 @@ calc (const struct ccase *c, const struct dataset *ds)
 static void
 precalc (struct casereader *input, struct dataset *ds)
 {
-  struct ccase c;
+  struct ccase *c;
   size_t i;
 
-  if (casereader_peek (input, 0, &c))
+  c = casereader_peek (input, 0);
+  if (c != NULL)
     {
-      output_split_file_values (ds, &c);
-      case_destroy (&c);
+      output_split_file_values (ds, c);
+      case_unref (c);
     }
 
   pool_destroy (data_pool);
index d6b4952c289532b0c0974ef0183b5b93585a4af3..26b903651eea06771c7b90799f9700162a9fb478 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -184,20 +184,21 @@ run_glm (struct casereader *input,
   int n_indep = 0;
   pspp_linreg_cache *model = NULL; 
   pspp_linreg_opts lopts;
-  struct ccase c;
+  struct ccase *c;
   size_t i;
   size_t n_all_vars;
   size_t n_data;               /* Number of valid cases. */
   struct casereader *reader;
   struct covariance_matrix *cov;
 
-  if (!casereader_peek (input, 0, &c))
+  c = casereader_peek (input, 0);
+  if (c == NULL)
     {
       casereader_destroy (input);
       return true;
     }
-  output_split_file_values (ds, &c);
-  case_destroy (&c);
+  output_split_file_values (ds, c);
+  case_unref (c);
 
   if (!v_dependent)
     {
@@ -237,12 +238,12 @@ run_glm (struct casereader *input,
       
       cov = covariance_matrix_init (n_all_vars, all_vars, ONE_PASS, PAIRWISE, MV_ANY);
       reader = casereader_create_counter (reader, &row, -1);
-      for (; casereader_read (reader, &c); case_destroy (&c))
+      for (; (c = casereader_read (reader)) != NULL; case_unref (c))
        {
          /* 
             Accumulate the covariance matrix.
          */
-         covariance_matrix_accumulate (cov, &c);
+         covariance_matrix_accumulate (cov, c, NULL, 0);
          n_data++;
        }
       covariance_matrix_compute (cov);
index c752d503bbbde6af9eeb0bd3036656e6de2c6019..04c83e1a0ed694456d3518e5c9ccad30101a2abb 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 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
@@ -45,7 +45,7 @@ npar_summary_calc_descriptives (struct descriptives *desc,
       double maximum = -DBL_MAX;
       double var;
       struct moments1 *moments = moments1_create (MOMENT_VARIANCE);
-      struct ccase c;
+      struct ccase *c;
       const struct variable *v = *vv++;
       struct casereader *pass;
 
@@ -54,14 +54,14 @@ npar_summary_calc_descriptives (struct descriptives *desc,
                                                &v, 1,
                                                filter, NULL, NULL);
       pass = casereader_create_filter_weight (pass, dict, NULL, NULL);
-      while (casereader_read(pass, &c))
+      while ((c = casereader_read (pass)) != NULL)
        {
-          double val = case_num (&c, v);
-          double w = dict_get_case_weight (dict, &c, NULL);
+          double val = case_num (c, v);
+          double w = dict_get_case_weight (dict, c, NULL);
           minimum = MIN (minimum, val);
           maximum = MAX (maximum, val);
           moments1_add (moments, val, w);
-         case_destroy (&c);
+         case_unref (c);
        }
       casereader_destroy (pass);
 
index b2e77f45d06a29ba3f4574406232b9f606ea28fb..be57eb24d5fbf6ac9830f5582655bd1028f89f30 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2007, 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
@@ -894,15 +894,16 @@ run_oneway (struct cmd_oneway *cmd,
   struct dictionary *dict = dataset_dict (ds);
   enum mv_class exclude;
   struct casereader *reader;
-  struct ccase c;
+  struct ccase *c;
 
-  if (!casereader_peek (input, 0, &c))
+  c = casereader_peek (input, 0);
+  if (c == NULL)
     {
       casereader_destroy (input);
       return;
     }
-  output_split_file_values (ds, &c);
-  case_destroy (&c);
+  output_split_file_values (ds, c);
+  case_unref (c);
 
   taint = taint_clone (casereader_get_taint (input));
 
@@ -923,13 +924,13 @@ run_oneway (struct cmd_oneway *cmd,
   input = casereader_create_filter_weight (input, dict, NULL, NULL);
 
   reader = casereader_clone (input);
-  for (; casereader_read (reader, &c); case_destroy (&c))
+  for (; (c = casereader_read (reader)) != NULL; case_unref (c))
     {
       size_t i;
 
-      const double weight = dict_get_case_weight (dict, &c, NULL);
+      const double weight = dict_get_case_weight (dict, c, NULL);
 
-      const union value *indep_val = case_data (&c, indep_var);
+      const union value *indep_val = case_data (c, indep_var);
       void **p = hsh_probe (global_group_hash, indep_val);
       if (*p == NULL)
         *p = value_dup (indep_val, var_get_width (indep_var));
@@ -938,7 +939,7 @@ run_oneway (struct cmd_oneway *cmd,
        {
          const struct variable *v = vars[i];
 
-         const union value *val = case_data (&c, v);
+         const union value *val = case_data (c, v);
 
           struct group_proc *gp = group_proc_get (vars[i]);
          struct hsh_table *group_hash = gp->group_hash;
index d3ee3707a4437112e84059270c2d16af7f11370c..3bbd39d1e0b0ea26ff7c1b78d67a2db35b5d8f4f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2006, 2007, 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
@@ -476,7 +476,7 @@ rank_sorted_file (struct casereader *input,
 {
   struct casereader *pass1, *pass2, *pass2_1;
   struct casegrouper *tie_grouper;
-  struct ccase c;
+  struct ccase *c;
   double w = 0.0;
   double cc = 0.0;
   int tie_group = 1;
@@ -489,8 +489,8 @@ rank_sorted_file (struct casereader *input,
   casereader_split (input, &pass1, &pass2);
 
   /* Pass 1: Get total group weight. */
-  for (; casereader_read (pass1, &c); case_destroy (&c))
-    w += dict_get_case_weight (dict, &c, NULL);
+  for (; (c = casereader_read (pass1)) != NULL; case_unref (c))
+    w += dict_get_case_weight (dict, c, NULL);
   casereader_destroy (pass1);
 
   /* Pass 2: Do ranking. */
@@ -507,21 +507,22 @@ rank_sorted_file (struct casereader *input,
                        casewriter_get_taint (output));
 
       /* Pass 2.1: Sum up weight for tied cases. */
-      for (; casereader_read (pass2_1, &c); case_destroy (&c))
-        tw += dict_get_case_weight (dict, &c, NULL);
+      for (; (c = casereader_read (pass2_1)) != NULL; case_unref (c))
+        tw += dict_get_case_weight (dict, c, NULL);
       cc += tw;
       casereader_destroy (pass2_1);
 
       /* Pass 2.2: Rank tied cases. */
-      while (casereader_read (pass2_2, &c))
+      while ((c = casereader_read (pass2_2)) != NULL)
         {
+          c = case_unshare (c);
           for (i = 0; i < n_rank_specs; ++i)
             {
               const struct variable *dst_var = rs[i].destvars[dest_idx];
-              double *dst_value = &case_data_rw (&c, dst_var)->f;
+              double *dst_value = &case_data_rw (c, dst_var)->f;
               *dst_value = rank_func[rs[i].rfunc] (tw, cc, cc_1, tie_group, w);
             }
-          casewriter_write (output, &c);
+          casewriter_write (output, c);
         }
       casereader_destroy (pass2_2);
 
@@ -532,11 +533,12 @@ rank_sorted_file (struct casereader *input,
 
 /* Transformation function to enumerate all the cases */
 static int
-create_resort_key (void *key_var_, struct ccase *cc, casenumber case_num)
+create_resort_key (void *key_var_, struct ccase **cc, casenumber case_num)
 {
   struct variable *key_var = key_var_;
 
-  case_data_rw(cc, key_var)->f = case_num;
+  *cc = case_unshare (*cc);
+  case_data_rw (*cc, key_var)->f = case_num;
 
   return TRNS_CONTINUE;
 }
index 4f6f0b862196b6a7365466147145714f3969bfa9..d82d5549adf3ea6e96ff308f442c03a55d94a7b3 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2005 Free Software Foundation, Inc.
+   Copyright (C) 2005, 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
@@ -542,7 +542,7 @@ regression_trns_free (void *t_)
   Gets the predicted values.
  */
 static int
-regression_trns_pred_proc (void *t_, struct ccase *c,
+regression_trns_pred_proc (void *t_, struct ccase **c,
                           casenumber case_idx UNUSED)
 {
   size_t i;
@@ -563,12 +563,12 @@ regression_trns_pred_proc (void *t_, struct ccase *c,
   n_vals = (*model->get_vars) (model, vars);
 
   vals = xnmalloc (n_vals, sizeof (*vals));
-  output = case_data_rw (c, model->pred);
-  assert (output != NULL);
+  *c = case_unshare (*c);
+  output = case_data_rw (*c, model->pred);
 
   for (i = 0; i < n_vals; i++)
     {
-      vals[i] = case_data (c, vars[i]);
+      vals[i] = case_data (*c, vars[i]);
     }
   output->f = (*model->predict) ((const struct variable **) vars,
                                 vals, model, n_vals);
@@ -581,7 +581,7 @@ regression_trns_pred_proc (void *t_, struct ccase *c,
   Gets the residuals.
  */
 static int
-regression_trns_resid_proc (void *t_, struct ccase *c,
+regression_trns_resid_proc (void *t_, struct ccase **c,
                            casenumber case_idx UNUSED)
 {
   size_t i;
@@ -603,14 +603,15 @@ regression_trns_resid_proc (void *t_, struct ccase *c,
   n_vals = (*model->get_vars) (model, vars);
 
   vals = xnmalloc (n_vals, sizeof (*vals));
-  output = case_data_rw (c, model->resid);
+  *c = case_unshare (*c);
+  output = case_data_rw (*c, model->resid);
   assert (output != NULL);
 
   for (i = 0; i < n_vals; i++)
     {
-      vals[i] = case_data (c, vars[i]);
+      vals[i] = case_data (*c, vars[i]);
     }
-  obs = case_data (c, model->depvar);
+  obs = case_data (*c, model->depvar);
   output->f = (*model->residual) ((const struct variable **) vars,
                                  vals, obs, model, n_vals);
   free (vals);
@@ -688,17 +689,21 @@ subcommand_save (struct dataset *ds, int save, pspp_linreg_cache ** models)
 
       for (lc = models; lc < models + cmd.n_dependent; lc++)
        {
-         assert (*lc != NULL);
-         assert ((*lc)->depvar != NULL);
-         if (cmd.a_save[REGRESSION_SV_RESID])
-           {
-             reg_save_var (ds, "RES", regression_trns_resid_proc, *lc,
-                           &(*lc)->resid, n_trns);
-           }
-         if (cmd.a_save[REGRESSION_SV_PRED])
+         if (*lc != NULL)
            {
-             reg_save_var (ds, "PRED", regression_trns_pred_proc, *lc,
-                           &(*lc)->pred, n_trns);
+             if ((*lc)->depvar != NULL)
+               {
+                 if (cmd.a_save[REGRESSION_SV_RESID])
+                   {
+                     reg_save_var (ds, "RES", regression_trns_resid_proc, *lc,
+                                   &(*lc)->resid, n_trns);
+                   }
+                 if (cmd.a_save[REGRESSION_SV_PRED])
+                   {
+                     reg_save_var (ds, "PRED", regression_trns_pred_proc, *lc,
+                                   &(*lc)->pred, n_trns);
+                   }
+               }
            }
        }
     }
@@ -821,7 +826,7 @@ prepare_categories (struct casereader *input,
                    struct moments_var *mom)
 {
   int n_data;
-  struct ccase c;
+  struct ccase *c;
   size_t i;
 
   assert (vars != NULL);
@@ -832,7 +837,7 @@ prepare_categories (struct casereader *input,
       cat_stored_values_create (vars[i]);
 
   n_data = 0;
-  for (; casereader_read (input, &c); case_destroy (&c))
+  for (; (c = casereader_read (input)) != NULL; case_unref (c))
     {
       /*
          The second condition ensures the program will run even if
@@ -841,7 +846,7 @@ prepare_categories (struct casereader *input,
        */
       for (i = 0; i < n_vars; i++)
        {
-         const union value *val = case_data (&c, vars[i]);
+         const union value *val = case_data (c, vars[i]);
          if (var_is_alpha (vars[i]))
            cat_value_update (vars[i], val);
          else
@@ -868,7 +873,7 @@ run_regression (struct casereader *input, struct cmd_regression *cmd,
   size_t i;
   int n_indep = 0;
   int k;
-  struct ccase c;
+  struct ccase *c;
   const struct variable **indep_vars;
   struct design_matrix *X;
   struct moments_var *mom;
@@ -878,13 +883,14 @@ run_regression (struct casereader *input, struct cmd_regression *cmd,
 
   assert (models != NULL);
 
-  if (!casereader_peek (input, 0, &c))
+  c = casereader_peek (input, 0);
+  if (c == NULL)
     {
       casereader_destroy (input);
       return true;
     }
-  output_split_file_values (ds, &c);
-  case_destroy (&c);
+  output_split_file_values (ds, c);
+  case_unref (c);
 
   if (!v_variables)
     {
@@ -916,7 +922,7 @@ run_regression (struct casereader *input, struct cmd_regression *cmd,
       const struct variable *dep_var;
       struct casereader *reader;
       casenumber row;
-      struct ccase c;
+      struct ccase *c;
       size_t n_data;           /* Number of valid cases. */
 
       dep_var = cmd->v_dependent[k];
@@ -955,18 +961,18 @@ run_regression (struct casereader *input, struct cmd_regression *cmd,
             The second pass fills the design matrix.
           */
          reader = casereader_create_counter (reader, &row, -1);
-         for (; casereader_read (reader, &c); case_destroy (&c))
+         for (; (c = casereader_read (reader)) != NULL; case_unref (c))
            {
              for (i = 0; i < n_indep; ++i)
                {
                  const struct variable *v = indep_vars[i];
-                 const union value *val = case_data (&c, v);
+                 const union value *val = case_data (c, v);
                  if (var_is_alpha (v))
                    design_matrix_set_categorical (X, row, v, val);
                  else
                    design_matrix_set_numeric (X, row, v, val);
                }
-             gsl_vector_set (Y, row, case_num (&c, dep_var));
+             gsl_vector_set (Y, row, case_num (c, dep_var));
            }
          /*
             Now that we know the number of coefficients, allocate space
index 8384bb350312100214e33cfcff1b1f5057d70703..25aff211dd739b8d63f8af886a565cadafdde11d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 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
@@ -304,7 +304,7 @@ run_reliability (struct casereader *input, struct dataset *ds UNUSED,
 {
   int i;
   int si;
-  struct ccase c;
+  struct ccase *c;
   casenumber n_missing ;
   casenumber n_valid = 0;
 
@@ -338,7 +338,7 @@ run_reliability (struct casereader *input, struct dataset *ds UNUSED,
                                          s, NULL);
     }
 
-  for (; casereader_read (input, &c); case_destroy (&c))
+  for (; (c = casereader_read (input)) != NULL; case_unref (c))
     {
       double weight = 1.0;
       n_valid ++;
@@ -348,9 +348,9 @@ run_reliability (struct casereader *input, struct dataset *ds UNUSED,
          struct cronbach *s = &rel->sc[si];
 
          for (i = 0 ; i < s->n_items ; ++i )
-           moments1_add (s->m[i], case_data (&c, s->items[i])->f, weight);
+           moments1_add (s->m[i], case_data (c, s->items[i])->f, weight);
 
-         moments1_add (s->total, case_data_idx (&c, s->totals_idx)->f, weight);
+         moments1_add (s->total, case_data_idx (c, s->totals_idx)->f, weight);
        }
     }
   casereader_destroy (input);
index 6d6dfd56cc6d0f432c936d52930d2ed85420c186..bc6023c72ebfaf7e08785ecc09dfa9a6b96c7669 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -1799,17 +1799,18 @@ calculate (struct cmd_t_test *cmd,
 
   struct casereader *pass1, *pass2, *pass3;
   struct taint *taint;
-  struct ccase c;
+  struct ccase *c;
 
   enum mv_class exclude = cmd->miss != TTS_INCLUDE ? MV_ANY : MV_SYSTEM;
 
-  if (!casereader_peek (input, 0, &c))
+  c = casereader_peek (input, 0);
+  if (c == NULL)
     {
       casereader_destroy (input);
       return;
     }
-  output_split_file_values (ds, &c);
-  case_destroy (&c);
+  output_split_file_values (ds, c);
+  case_unref (c);
 
   if ( cmd->miss == TTS_LISTWISE )
     input = casereader_create_filter_missing (input,
@@ -1823,8 +1824,8 @@ calculate (struct cmd_t_test *cmd,
   casereader_split (input, &pass1, &pass2);
 
   common_precalc (cmd);
-  for (; casereader_read (pass1, &c); case_destroy (&c))
-    common_calc (dict, &c, cmd, exclude);
+  for (; (c = casereader_read (pass1)) != NULL; case_unref (c))
+    common_calc (dict, c, cmd, exclude);
   casereader_destroy (pass1);
   common_postcalc (cmd);
 
@@ -1832,22 +1833,22 @@ calculate (struct cmd_t_test *cmd,
     {
     case T_1_SAMPLE:
       one_sample_precalc (cmd);
-      for (; casereader_read (pass2, &c); case_destroy (&c))
-        one_sample_calc (dict, &c, cmd, exclude);
+      for (; (c = casereader_read (pass2)) != NULL; case_unref (c))
+        one_sample_calc (dict, c, cmd, exclude);
       one_sample_postcalc (cmd);
       break;
     case T_PAIRED:
       paired_precalc (cmd);
-      for (; casereader_read (pass2, &c); case_destroy (&c))
-        paired_calc (dict, &c, cmd, exclude);
+      for (; (c = casereader_read (pass2)) != NULL; case_unref (c))
+        paired_calc (dict, c, cmd, exclude);
       paired_postcalc (cmd);
       break;
     case T_IND_SAMPLES:
       pass3 = casereader_clone (pass2);
 
       group_precalc (cmd);
-      for (; casereader_read (pass2, &c); case_destroy (&c))
-        group_calc (dict, &c, cmd, exclude);
+      for (; (c = casereader_read (pass2)) != NULL; case_unref (c))
+        group_calc (dict, c, cmd, exclude);
       group_postcalc (cmd);
 
       levene (dict, pass3, indep_var, cmd->n_variables, cmd->v_variables,
index 2f5bbea892745a99fb33fdbede97ce6baa29319c..e44233a7ab7904fb437a1988f6505cb3af4559cf 100644 (file)
@@ -1,5 +1,5 @@
 /* Pspp - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 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
 #include <output/table.h>
 #include <data/procedure.h>
 #include <data/dictionary.h>
-#include <misc/wx-mp-sr.h>
+#include <math/wilcoxon-sig.h>
 #include <gsl/gsl_cdf.h>
 #include <unistd.h>
 #include <signal.h>
 #include <libpspp/assertion.h>
 
-static double timed_wilcoxon_significance (double w, long int n, double timer);
-
-
 static double
 append_difference (const struct ccase *c, casenumber n UNUSED, void *aux)
 {
@@ -88,7 +85,7 @@ wilcoxon_execute (const struct dataset *ds,
     {
       struct casereader *r = casereader_clone (input);
       struct casewriter *writer;
-      struct ccase c;
+      struct ccase *c;
       struct subcase ordering;
       variable_pair *vp = &t2s->pairs[i];
 
@@ -105,41 +102,37 @@ wilcoxon_execute (const struct dataset *ds,
       writer = sort_create_writer (&ordering, reader_width);
       subcase_destroy (&ordering);
 
-      while (casereader_read (r, &c))
+      for (; (c = casereader_read (r)) != NULL; case_unref (c))
        {
-         struct ccase output;
-         double d = append_difference (&c, 0, vp);
-
-         case_create (&output, reader_width);
+         struct ccase *output = case_create (reader_width);
+         double d = append_difference (c, 0, vp);
 
          if (d > 0)
            {
-             case_data_rw (&output, ws[i].sign)->f = 1.0;
+             case_data_rw (output, ws[i].sign)->f = 1.0;
 
            }
          else if (d < 0)
            {
-             case_data_rw (&output, ws[i].sign)->f = -1.0;
+             case_data_rw (output, ws[i].sign)->f = -1.0;
            }
          else
            {
              double w = 1.0;
              if (weight)
-               w = case_data (&c, weight)->f;
+               w = case_data (c, weight)->f;
 
              /* Central point values should be dropped */
              ws[i].n_zeros += w;
-             case_destroy (&c);
-             continue;
+              continue;
            }
 
-         case_data_rw (&output, ws[i].absdiff)->f = fabs (d);
+         case_data_rw (output, ws[i].absdiff)->f = fabs (d);
 
          if (weight)
-          case_data_rw (&output, weightx)->f = case_data (&c, weight)->f;
+          case_data_rw (output, weightx)->f = case_data (c, weight)->f;
 
-         casewriter_write (writer, &output);
-         case_destroy (&c);
+         casewriter_write (writer, output);
        }
       casereader_destroy (r);
       ws[i].reader = casewriter_make_reader (writer);
@@ -148,7 +141,7 @@ wilcoxon_execute (const struct dataset *ds,
   for (i = 0 ; i < t2s->n_pairs; ++i )
     {
       struct casereader *rr ;
-      struct ccase c;
+      struct ccase *c;
       enum rank_error err = 0;
 
       rr = casereader_create_append_rank (ws[i].reader, ws[i].absdiff,
@@ -156,13 +149,13 @@ wilcoxon_execute (const struct dataset *ds,
                                          distinct_callback, &ws[i]
                                          );
 
-      while (casereader_read (rr, &c))
+      for (; (c = casereader_read (rr)) != NULL; case_unref (c))
        {
-         double sign = case_data (&c, ws[i].sign)->f;
-         double rank = case_data_idx (&c, weight ? 3 : 2)->f;
+         double sign = case_data (c, ws[i].sign)->f;
+         double rank = case_data_idx (c, weight ? 3 : 2)->f;
          double w = 1.0;
          if (weight)
-           w = case_data (&c, weightx)->f;
+           w = case_data (c, weightx)->f;
 
          if ( sign > 0 )
            {
@@ -176,8 +169,6 @@ wilcoxon_execute (const struct dataset *ds,
            }
          else
            NOT_REACHED ();
-
-         case_destroy (&c);
        }
 
       casereader_destroy (rr);
@@ -286,7 +277,7 @@ static void
 show_tests_box (const struct wilcoxon_state *ws,
                const struct two_sample_test *t2s,
                bool exact,
-               double timer
+               double timer UNUSED
                )
 {
   size_t i;
@@ -348,14 +339,10 @@ show_tests_box (const struct wilcoxon_state *ws,
 
       if (exact)
        {
-         double p =
-           timed_wilcoxon_significance (ws[i].positives.sum,
-                                        n,
-                                        timer );
-
-         if ( p == SYSMIS)
+         double p = LevelOfSignificanceWXMPSR (ws[i].positives.sum, n);
+         if (p < 0)
            {
-             msg (MW, _("Exact significance was not calculated after %.2f minutes. Skipping test."), timer);
+             msg (MW, ("Too many pairs to calculate exact significance."));
            }
          else
            {
@@ -371,48 +358,3 @@ show_tests_box (const struct wilcoxon_state *ws,
 
   tab_submit (table);
 }
-
-\f
-
-#include <setjmp.h>
-
-static sigjmp_buf env;
-
-static void
-give_up_callback (int signal UNUSED)
-{
-  siglongjmp (env, 1);
-}
-
-static double
-timed_wilcoxon_significance (double w, long int n, double timer)
-{
-  double p = SYSMIS;
-
-  sigset_t set;
-
-  struct sigaction timeout_action;
-  struct sigaction old_action;
-
-  if (timer <= 0 )
-    return LevelOfSignificanceWXMPSR (w, n);
-
-  sigemptyset (&set);
-
-  timeout_action.sa_mask = set;
-  timeout_action.sa_flags = 0;
-
-  timeout_action.sa_handler = give_up_callback;
-
-  if ( 0 == sigsetjmp (env, 1))
-    {
-      sigaction (SIGALRM, &timeout_action, &old_action);
-      alarm (timer * 60.0);
-
-      p = LevelOfSignificanceWXMPSR (w, n);
-    }
-
-  sigaction (SIGALRM, &old_action, NULL);
-
-  return p;
-}
index b3b2856d4262f36c88db1d4142f64a99039892ea..ccfee80579400e3cd618012114a7551b16d60397 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -80,14 +80,15 @@ check_datasheet_casereader (struct mc *mc, struct casereader *reader,
               casereader_get_value_cnt (reader), column_cnt);
   else
     {
-      struct ccase c;
+      struct ccase *c;
       size_t row;
 
       for (row = 0; row < row_cnt; row++)
         {
           size_t col;
 
-          if (!casereader_read (reader, &c))
+          c = casereader_read (reader);
+          if (c == NULL)
             {
               mc_error (mc, "casereader_read failed reading row %zu of %zu "
                         "(%zu columns)", row, row_cnt, column_cnt);
@@ -95,16 +96,17 @@ check_datasheet_casereader (struct mc *mc, struct casereader *reader,
             }
 
           for (col = 0; col < column_cnt; col++)
-            if (case_num_idx (&c, col) != array[row][col])
+            if (case_num_idx (c, col) != array[row][col])
               mc_error (mc, "element %zu,%zu (of %zu,%zu) differs: "
                         "%g != %g",
                         row, col, row_cnt, column_cnt,
-                        case_num_idx (&c, col), array[row][col]);
+                        case_num_idx (c, col), array[row][col]);
 
-         case_destroy (&c);
+         case_unref (c);
         }
 
-      if (casereader_read (reader, &c))
+      c = casereader_read (reader);
+      if (c != NULL)
         mc_error (mc, "casereader has extra cases (expected %zu)", row_cnt);
     }
 }
@@ -253,17 +255,17 @@ datasheet_mc_init (struct mc *mc)
       writer = mem_writer_create (params->backing_cols);
       for (row = 0; row < params->backing_rows; row++)
         {
-          struct ccase c;
+          struct ccase *c;
           int col;
 
-          case_create (&c, params->backing_cols);
+          c = case_create (params->backing_cols);
           for (col = 0; col < params->backing_cols; col++)
             {
               double value = params->next_value++;
               data[row][col] = value;
-              case_data_rw_idx (&c, col)->f = value;
+              case_data_rw_idx (c, col)->f = value;
             }
-          casewriter_write (writer, &c);
+          casewriter_write (writer, c);
         }
       reader = casewriter_make_reader (writer);
       assert (reader != NULL);
@@ -371,7 +373,7 @@ datasheet_mc_mutate (struct mc *mc, const void *ods_)
       if (mc_include_state (mc))
         {
           struct datasheet *ds;
-          struct ccase c[MAX_ROWS];
+          struct ccase *c[MAX_ROWS];
           size_t i, j;
 
           clone_model (ods, odata, &ds, data);
@@ -379,15 +381,15 @@ datasheet_mc_mutate (struct mc *mc, const void *ods_)
 
           for (i = 0; i < cnt; i++)
             {
-              case_create (&c[i], column_cnt);
+              c[i] = case_create (column_cnt);
               for (j = 0; j < column_cnt; j++)
-                case_data_rw_idx (&c[i], j)->f = params->next_value++;
+                case_data_rw_idx (c[i], j)->f = params->next_value++;
             }
 
           insert_range (data, row_cnt, sizeof data[pos], pos, cnt);
           for (i = 0; i < cnt; i++)
             for (j = 0; j < column_cnt; j++)
-              data[i + pos][j] = case_num_idx (&c[i], j);
+              data[i + pos][j] = case_num_idx (c[i], j);
 
           if (!datasheet_insert_rows (ds, pos, c, cnt))
             mc_error (mc, "datasheet_insert_rows failed");
index bd0e492dc00a28f51ea4264a59318fc3d7933048..d5a1c096d68b3ad88c503ab961140c8037b6625e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -51,7 +51,7 @@ void datasheet_move_columns (struct datasheet *,
 /* Rows. */
 casenumber datasheet_get_row_cnt (const struct datasheet *);
 bool datasheet_insert_rows (struct datasheet *,
-                            casenumber before, struct ccase[],
+                            casenumber before, struct ccase *rows[],
                             casenumber cnt);
 void datasheet_delete_rows (struct datasheet *,
                             casenumber first, casenumber cnt);
@@ -60,7 +60,7 @@ void datasheet_move_rows (struct datasheet *,
                           size_t cnt);
 
 /* Data. */
-bool datasheet_get_row (const struct datasheet *, casenumber, struct ccase *);
+struct ccase *datasheet_get_row (const struct datasheet *, casenumber);
 bool datasheet_put_row (struct datasheet *, casenumber, struct ccase *);
 bool datasheet_get_value (const struct datasheet *, casenumber, size_t column,
                           union value *, int width);
index 8e69dab50c6260f63795d569c910ab48cd743c47..fe98aeb87f3347b82b61853adc70360cee87f132 100644 (file)
@@ -16,7 +16,9 @@
 
 #include <config.h>
 #include <ctype.h>
+#include <errno.h>
 #include <stdlib.h>
+#include <string.h>
 #include <language/command.h>
 #include <libpspp/message.h>
 #include <libpspp/getl.h>
@@ -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;
 }
index f17798f77722a35cb2597a82f5ecaea4ccfcced7..9f65491ef50afdd1485d74e7faf84d49e635704d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -112,14 +112,17 @@ cmd_compute (struct lexer *lexer, struct dataset *ds)
 
 /* Handle COMPUTE or IF with numeric target variable. */
 static int
-compute_num (void *compute_, struct ccase *c, casenumber case_num)
+compute_num (void *compute_, struct ccase **c, casenumber case_num)
 {
   struct compute_trns *compute = compute_;
 
   if (compute->test == NULL
-      || expr_evaluate_num (compute->test, c, case_num) == 1.0)
-    case_data_rw (c, compute->variable)->f
-      = expr_evaluate_num (compute->rvalue, c, case_num);
+      || expr_evaluate_num (compute->test, *c, case_num) == 1.0)
+    {
+      *c = case_unshare (*c);
+      case_data_rw (*c, compute->variable)->f
+        = expr_evaluate_num (compute->rvalue, *c, case_num);
+    }
 
   return TRNS_CONTINUE;
 }
@@ -127,17 +130,17 @@ compute_num (void *compute_, struct ccase *c, casenumber case_num)
 /* Handle COMPUTE or IF with numeric vector element target
    variable. */
 static int
-compute_num_vec (void *compute_, struct ccase *c, casenumber case_num)
+compute_num_vec (void *compute_, struct ccase **c, casenumber case_num)
 {
   struct compute_trns *compute = compute_;
 
   if (compute->test == NULL
-      || expr_evaluate_num (compute->test, c, case_num) == 1.0)
+      || expr_evaluate_num (compute->test, *c, case_num) == 1.0)
     {
       double index;     /* Index into the vector. */
       int rindx;        /* Rounded index value. */
 
-      index = expr_evaluate_num (compute->element, c, case_num);
+      index = expr_evaluate_num (compute->element, *c, case_num);
       rindx = floor (index + EPSILON);
       if (index == SYSMIS
           || rindx < 1 || rindx > vector_get_var_cnt (compute->vector))
@@ -152,8 +155,10 @@ compute_num_vec (void *compute_, struct ccase *c, casenumber case_num)
                  index, vector_get_name (compute->vector));
           return TRNS_CONTINUE;
         }
-      case_data_rw (c, vector_get_var (compute->vector, rindx - 1))->f
-        = expr_evaluate_num (compute->rvalue, c, case_num);
+
+      *c = case_unshare (*c);
+      case_data_rw (*c, vector_get_var (compute->vector, rindx - 1))->f
+        = expr_evaluate_num (compute->rvalue, *c, case_num);
     }
 
   return TRNS_CONTINUE;
@@ -161,14 +166,18 @@ compute_num_vec (void *compute_, struct ccase *c, casenumber case_num)
 
 /* Handle COMPUTE or IF with string target variable. */
 static int
-compute_str (void *compute_, struct ccase *c, casenumber case_num)
+compute_str (void *compute_, struct ccase **c, casenumber case_num)
 {
   struct compute_trns *compute = compute_;
 
   if (compute->test == NULL
-      || expr_evaluate_num (compute->test, c, case_num) == 1.0)
-    expr_evaluate_str (compute->rvalue, c, case_num,
-                       case_data_rw (c, compute->variable)->s, compute->width);
+      || expr_evaluate_num (compute->test, *c, case_num) == 1.0)
+    {
+      *c = case_unshare (*c);
+      expr_evaluate_str (compute->rvalue, *c, case_num,
+                         case_data_rw (*c, compute->variable)->s,
+                         compute->width);
+    }
 
   return TRNS_CONTINUE;
 }
@@ -176,18 +185,18 @@ compute_str (void *compute_, struct ccase *c, casenumber case_num)
 /* Handle COMPUTE or IF with string vector element target
    variable. */
 static int
-compute_str_vec (void *compute_, struct ccase *c, casenumber case_num)
+compute_str_vec (void *compute_, struct ccase **c, casenumber case_num)
 {
   struct compute_trns *compute = compute_;
 
   if (compute->test == NULL
-      || expr_evaluate_num (compute->test, c, case_num) == 1.0)
+      || expr_evaluate_num (compute->test, *c, case_num) == 1.0)
     {
       double index;             /* Index into the vector. */
       int rindx;                /* Rounded index value. */
       struct variable *vr;      /* Variable reference by indexed vector. */
 
-      index = expr_evaluate_num (compute->element, c, case_num);
+      index = expr_evaluate_num (compute->element, *c, case_num);
       rindx = floor (index + EPSILON);
       if (index == SYSMIS)
         {
@@ -205,8 +214,9 @@ compute_str_vec (void *compute_, struct ccase *c, casenumber case_num)
         }
 
       vr = vector_get_var (compute->vector, rindx - 1);
-      expr_evaluate_str (compute->rvalue, c, case_num,
-                         case_data_rw (c, vr)->s,
+      *c = case_unshare (*c);
+      expr_evaluate_str (compute->rvalue, *c, case_num,
+                         case_data_rw (*c, vr)->s,
                          var_get_width (vr));
     }
 
index 1c9b4d65735f9487b147da120585465b7501ea0d..6e234c4b23728fa9e1e886db9a9585e9fd5c5274 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -268,8 +268,8 @@ parse_string_criteria (struct lexer *lexer, struct pool *pool, struct criteria *
 /* Transformation. */
 
 /* Counts the number of values in case C matching CRIT. */
-static inline int
-count_numeric (struct criteria *crit, struct ccase *c)
+static int
+count_numeric (struct criteria *crit, const struct ccase *c)
 {
   int counter = 0;
   size_t i;
@@ -302,8 +302,8 @@ count_numeric (struct criteria *crit, struct ccase *c)
 }
 
 /* Counts the number of values in case C matching CRIT. */
-static inline int
-count_string (struct criteria *crit, struct ccase *c)
+static int
+count_string (struct criteria *crit, const struct ccase *c)
 {
   int counter = 0;
   size_t i;
@@ -325,12 +325,13 @@ count_string (struct criteria *crit, struct ccase *c)
 
 /* Performs the COUNT transformation T on case C. */
 static int
-count_trns_proc (void *trns_, struct ccase *c,
+count_trns_proc (void *trns_, struct ccase **c,
                  casenumber case_num UNUSED)
 {
   struct count_trns *trns = trns_;
   struct dst_var *dv;
 
+  *c = case_unshare (*c);
   for (dv = trns->dst_vars; dv; dv = dv->next)
     {
       struct criteria *crit;
@@ -339,10 +340,10 @@ count_trns_proc (void *trns_, struct ccase *c,
       counter = 0;
       for (crit = dv->crit; crit; crit = crit->next)
        if (var_is_numeric (crit->vars[0]))
-         counter += count_numeric (crit, c);
+         counter += count_numeric (crit, *c);
        else
-         counter += count_string (crit, c);
-      case_data_rw (c, dv->var)->f = counter;
+         counter += count_string (crit, *c);
+      case_data_rw (*c, dv->var)->f = counter;
     }
   return TRNS_CONTINUE;
 }
index ad3425c8a28dadd966ef5a59d26bd618c0f64e20..d1cfabf6676478deb66baca38b371431c5ddd1d6 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
 #include <language/command.h>
 #include <language/lexer/lexer.h>
 
-static int trns_fail (void *x, struct ccase *c, casenumber n);
+static int trns_fail (void *x, struct ccase **c, casenumber n);
 
 
 \f
 /* A transformation which is guaranteed to fail. */
 
 static int
-trns_fail (void *x UNUSED, struct ccase *c UNUSED,
+trns_fail (void *x UNUSED, struct ccase **c UNUSED,
           casenumber n UNUSED)
 {
   return TRNS_ERROR;
index bdff1ac5246ed80e9afd428a4ec4518b077a9684..e2074823f9df4185aa9db4bcd29a6c6615e25bd3 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -647,18 +647,19 @@ find_src_string (struct recode_trns *trns, const char *value, const struct varia
 
 /* Performs RECODE transformation. */
 static int
-recode_trns_proc (void *trns_, struct ccase *c, casenumber case_idx UNUSED)
+recode_trns_proc (void *trns_, struct ccase **c, casenumber case_idx UNUSED)
 {
   struct recode_trns *trns = trns_;
   size_t i;
 
+  *c = case_unshare (*c);
   for (i = 0; i < trns->var_cnt; i++)
     {
       const struct variable *src_var = trns->src_vars[i];
       const struct variable *dst_var = trns->dst_vars[i];
 
-      const union value *src_data = case_data (c, src_var);
-      union value *dst_data = case_data_rw (c, dst_var);
+      const union value *src_data = case_data (*c, src_var);
+      union value *dst_data = case_data_rw (*c, dst_var);
 
       const struct map_out *out;
 
index 632009eddc84cabb12dc026df09388b0a9136a12..6fbc758c2e1329f41d57d626daa9eb8ca75b495a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -116,7 +116,7 @@ cmd_sample (struct lexer *lexer, struct dataset *ds)
 
 /* Executes a SAMPLE transformation. */
 static int
-sample_trns_proc (void *t_, struct ccase *c UNUSED,
+sample_trns_proc (void *t_, struct ccase **c UNUSED,
                   casenumber case_num UNUSED)
 {
   struct sample_trns *t = t_;
index 5576c420fd903ee483ea5f5859e4ee89f31d9727..85f616d536fb3ad39e670f517f9f892488a9a8b8 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
@@ -70,11 +70,11 @@ cmd_select_if (struct lexer *lexer, struct dataset *ds)
 
 /* Performs the SELECT IF transformation T on case C. */
 static int
-select_if_proc (void *t_, struct ccase *c,
+select_if_proc (void *t_, struct ccase **c,
                 casenumber case_num)
 {
   struct select_if_trns *t = t_;
-  return (expr_evaluate_num (t->e, c, case_num) == 1.0
+  return (expr_evaluate_num (t->e, *c, case_num) == 1.0
           ? TRNS_CONTINUE : TRNS_DROP_CASE);
 }
 
index 0c20643bbc71908cd818b1d1de81d9430ba40539..dc512bb288907f59cc668e1ea989e8c7858f6916 100644 (file)
@@ -75,10 +75,14 @@ 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
+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. */">> $@
+       echo "   Generated by src/libpspp/automake.mk --- Do not edit.">> $@
+       echo "" >> $@
+       echo "   The following line is for the benefit of the perl module" >>$@
+       echo "\$$VERSION='"@VERSION@"';" >> $@
+       echo "*/" >> $@
        echo "#include \"version.h\"" >> $@
        echo "const char bare_version[] = \"@VERSION@\";" >> $@
        echo "const char version[] = \"GNU @PACKAGE@ @VERSION@\";" >> $@
index 695b713287b4d55096cd4ddab330d30ea7f35f03..227109145528d318f3963e7b3e295d11ef8602e9 100644 (file)
@@ -99,9 +99,11 @@ msg_destroy(struct msg *m)
 void
 msg_emit (struct msg *m)
 {
-  get_msg_location (s_stream, &m->where);
+  if ( s_stream )
+    get_msg_location (s_stream, &m->where);
+
   if (!messages_disabled)
-    msg_handler (m);
+     msg_handler (m);
   free (m->text);
 }
 
index d082672060f5235d6610939221365663fb5652b8..f054c9ef28833046760957f2de9aabc7da6ec8dc 100644 (file)
@@ -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
@@ -1190,48 +1190,42 @@ ds_cstr (const struct string *st_)
   return st->ss.string;
 }
 
-/* Appends to ST a newline-terminated line read from STREAM, but
-   no more than MAX_LENGTH characters.
-   Newline is the last character of ST on return, if encountering
-   a newline was the reason for terminating.
-   Returns true if at least one character was read from STREAM
-   and appended to ST, false if no characters at all were read
-   before an I/O error or end of file was encountered (or
-   MAX_LENGTH was 0). */
+/* Reads characters from STREAM and appends them to ST, stopping
+   after MAX_LENGTH characters, after appending a newline, or
+   after an I/O error or end of file was encountered, whichever
+   comes first.  Returns true if at least one character was added
+   to ST, false if no characters were read before an I/O error or
+   end of file (or if MAX_LENGTH was 0).
+
+   This function accepts LF, CR LF, and CR sequences as new-line,
+   and translates each of them to a single '\n' new-line
+   character in ST. */
 bool
 ds_read_line (struct string *st, FILE *stream, size_t max_length)
 {
-  if (!st->ss.length && max_length == SIZE_MAX)
-    {
-      size_t capacity = st->capacity ? st->capacity + 1 : 0;
-      ssize_t n = getline (&st->ss.string, &capacity, stream);
-      if (capacity)
-        st->capacity = capacity - 1;
-      if (n > 0)
-        {
-          st->ss.length = n;
-          return true;
-        }
-      else
-        return false;
-    }
-  else
+  size_t length;
+
+  for (length = 0; length < max_length; length++)
     {
-      size_t length;
+      int c = getc (stream);
+      if (c == EOF)
+        break;
 
-      for (length = 0; length < max_length; length++)
+      if (c == '\r')
         {
-          int c = getc (stream);
-          if (c == EOF)
-            break;
-
-          ds_put_char (st, c);
-          if (c == '\n')
-            return true;
+          c = getc (stream);
+          if (c != '\n')
+            {
+              ungetc (c, stream);
+              c = '\n';
+            }
         }
-
-      return length > 0;
+      ds_put_char (st, c);
+      if (c == '\n')
+        return true;
     }
+
+  return length > 0;
 }
 
 /* Removes a comment introduced by `#' from ST,
index e463088779f385fa0b58ccc7edc6ba720c1bddc8..cadfb90079ebf429083edede4d7cfbb9ec4a8f8f 100644 (file)
@@ -32,4 +32,5 @@ src_math_libpspp_math_la_SOURCES = \
         src/math/statistic.h \
        src/math/sort.c src/math/sort.h \
        src/math/trimmed-mean.c src/math/trimmed-mean.h \
-       src/math/tukey-hinges.c src/math/tukey-hinges.h 
+       src/math/tukey-hinges.c src/math/tukey-hinges.h \
+       src/math/wilcoxon-sig.c src/math/wilcoxon-sig.h
index 32ca9bca9f7a20f1d7bd6d899027af54b6639998..e1b612affe747949867ea53efadfb4de64b1c5a5 100644 (file)
@@ -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);
index 33a5d750533be2526ed6f23042ee2512da2dc057..b692e7e8003e4ee852a09a22c8acda31864c4901 100644 (file)
@@ -22,6 +22,7 @@
 #define COVARIANCE_MATRIX_H
 
 #include <math/design-matrix.h>
+#include <math/interaction.h>
 
 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
index c8ead42912f17787dc4c01e8e46ced248e255a59..33da8423bd7c7545a69e4c51a1d0a9a5abd4318d 100644 (file)
@@ -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
   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 <config.h>
 #include <assert.h>
 #include <gsl/gsl_math.h>
 #include <gsl/gsl_vector.h>
-#include <data/category.h>
+#include <data/value.h>
 #include <data/variable.h>
-#include "interaction.h"
+#include <math/interaction.h>
+#include <string.h>
+#include <xalloc.h>
 
-#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;
 }
+  
index 070060781635131ca91f05fb6ac7e787f421f48d..73b440be32b014cc4da06c715266efb1b4e6da18 100644 (file)
@@ -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
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
-gsl_vector *
-get_interaction (union value **, const struct variable **, size_t);
+#ifndef INTERACTION_H
+#define INTERACTION_H
+#include <data/case.h>
+
+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
index 3f8ddb29bd0b3c76d524da12c3f273643acfe0ec..7bd582105f940c28ffeb26506d4c5fe941ff728d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004, 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
@@ -118,7 +118,7 @@ levene(const struct dictionary *dict,
        enum mv_class exclude)
 {
   struct casereader *pass1, *pass2;
-  struct ccase c;
+  struct ccase *c;
   struct levene_info l;
 
   l.n_dep      = n_dep;
@@ -131,14 +131,14 @@ levene(const struct dictionary *dict,
   casereader_split (reader, &pass1, &pass2);
 
   levene_precalc (&l);
-  for (; casereader_read (pass1, &c); case_destroy (&c))
-    levene_calc (dict, &c, &l);
+  for (; (c = casereader_read (pass1)) != NULL; case_unref (c))
+    levene_calc (dict, c, &l);
   casereader_destroy (pass1);
   levene_postcalc (&l);
 
   levene2_precalc(&l);
-  for (; casereader_read (pass2, &c); case_destroy (&c))
-    levene2_calc (dict, &c, &l);
+  for (; (c = casereader_read (pass2)) != NULL; case_unref (c))
+    levene2_calc (dict, c, &l);
   casereader_destroy (pass2);
   levene2_postcalc (&l);
 
index b84122982e04f19fedaf1c2a0e542e58214546d0..2ff57c6e5ba6fa0a88a9237f95782cb55332bbd6 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 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
@@ -36,7 +36,7 @@
 struct merge_input
   {
     struct casereader *reader;
-    struct ccase c;
+    struct ccase *c;
   };
 
 struct merge
@@ -111,7 +111,8 @@ read_input_case (struct merge *m, size_t idx)
 {
   struct merge_input *i = &m->inputs[idx];
 
-  if (casereader_read (i->reader, &i->c))
+  i->c = casereader_read (i->reader);
+  if (i->c)
     return true;
   else
     {
@@ -144,11 +145,11 @@ do_merge (struct merge *m)
 
       min = 0;
       for (i = 1; i < m->input_cnt; i++)
-        if (subcase_compare_3way (&m->ordering, &m->inputs[i].c,
-                                  &m->ordering, &m->inputs[min].c) < 0)
+        if (subcase_compare_3way (&m->ordering, m->inputs[i].c,
+                                  &m->ordering, m->inputs[min].c) < 0)
           min = i;
 
-      casewriter_write (w, &m->inputs[min].c);
+      casewriter_write (w, m->inputs[min].c);
       read_input_case (m, min);
     }
 
index e189b47091faee8304ee1a557042cd0f2cff873c..99584a5105b75879517e4b30982e9d78280a5dd1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 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
@@ -37,7 +37,7 @@ static void
 acc (struct statistic *s, const struct ccase *cx UNUSED,
      double c, double cc, double y)
 {
-  struct ccase cp;
+  struct ccase *cp;
   struct np *np = (struct np *) s;
   double rank = np->prev_cc + (c + 1) / 2.0;
 
@@ -56,13 +56,11 @@ acc (struct statistic *s, const struct ccase *cx UNUSED,
   maximize (&np->y_max, y);
   minimize (&np->y_min, y);
 
-  case_create (&cp, n_NP_IDX);
-
-  case_data_rw_idx (&cp, NP_IDX_Y)->f = y;
-  case_data_rw_idx (&cp, NP_IDX_NS)->f = ns;
-  case_data_rw_idx (&cp, NP_IDX_DNS)->f = dns;
-
-  casewriter_write (np->writer, &cp);
+  cp = case_create (n_NP_IDX);
+  case_data_rw_idx (cp, NP_IDX_Y)->f = y;
+  case_data_rw_idx (cp, NP_IDX_NS)->f = ns;
+  case_data_rw_idx (cp, NP_IDX_DNS)->f = dns;
+  casewriter_write (np->writer, cp);
 
   np->prev_cc = cc;
 }
index ca4160f4fdf6f52b09d82972edf10f6d8f4f6703..1b6aa131ea745ba6c0b55b33a54f3a6d39ceddbe 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 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
@@ -113,44 +113,42 @@ order_stats_accumulate (struct order_stats **os, size_t nos,
                        const struct variable *var,
                        enum mv_class exclude)
 {
-  struct ccase cx;
-  struct ccase prev_cx;
+  struct ccase *cx;
+  struct ccase *prev_cx = NULL;
   double prev_value = -DBL_MAX;
 
   double cc_i = 0;
   double c_i = 0;
 
-  case_nullify (&prev_cx);
-
-  for (; casereader_read (reader, &cx); case_destroy (&cx))
+  for (; (cx = casereader_read (reader)) != NULL; case_unref (cx))
     {
-      const double weight = wv ? case_data (&cx, wv)->f : 1.0;
-      const double this_value = case_data (&cx, var)->f;
+      const double weight = wv ? case_data (cx, wv)->f : 1.0;
+      const double this_value = case_data (cx, var)->f;
 
       /* The casereader MUST be sorted */
       assert (this_value >= prev_value);
 
-      if ( var_is_value_missing (var, case_data (&cx, var), exclude))
+      if ( var_is_value_missing (var, case_data (cx, var), exclude))
        continue;
 
-      case_destroy (&prev_cx);
+      case_unref (prev_cx);
 
       if ( prev_value == -DBL_MAX || prev_value == this_value)
        c_i += weight;
 
       if ( prev_value > -DBL_MAX && this_value > prev_value)
        {
-         update_k_values (&prev_cx, prev_value, c_i, cc_i, os, nos);
+         update_k_values (prev_cx, prev_value, c_i, cc_i, os, nos);
          c_i = weight;
        }
 
       cc_i += weight;
       prev_value = this_value;
-      case_clone (&prev_cx, &cx);
+      prev_cx = case_ref (cx);
     }
 
-  update_k_values (&prev_cx, prev_value, c_i, cc_i, os, nos);
-  case_destroy (&prev_cx);
+  update_k_values (prev_cx, prev_value, c_i, cc_i, os, nos);
+  case_unref (prev_cx);
 
   casereader_destroy (reader);
 }
index 9e860c4657a83029fc923e835f30579b39d2ea1c..67aa32d29048fffbb5e7b3c03b371b8db9c88a62 100644 (file)
@@ -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
@@ -48,7 +48,7 @@ struct sort_writer
 
     struct casewriter *run;
     casenumber run_id;
-    struct ccase run_end;
+    struct ccase *run_end;
   };
 
 static struct casewriter_class sort_casewriter_class;
@@ -58,7 +58,7 @@ static void pqueue_destroy (struct pqueue *);
 static bool pqueue_is_full (const struct pqueue *);
 static bool pqueue_is_empty (const struct pqueue *);
 static void pqueue_push (struct pqueue *, struct ccase *, casenumber);
-static void pqueue_pop (struct pqueue *, struct ccase *, casenumber *);
+static struct ccase *pqueue_pop (struct pqueue *, casenumber *);
 
 static void output_record (struct sort_writer *);
 
@@ -74,7 +74,7 @@ sort_create_writer (const struct subcase *ordering, size_t value_cnt)
   sort->pqueue = pqueue_create (ordering, value_cnt);
   sort->run = NULL;
   sort->run_id = 0;
-  case_nullify (&sort->run_end);
+  sort->run_end = NULL;
 
   return casewriter_create (value_cnt, &sort_casewriter_class, sort);
 }
@@ -89,9 +89,9 @@ sort_casewriter_write (struct casewriter *writer UNUSED, void *sort_,
   if (pqueue_is_full (sort->pqueue))
     output_record (sort);
 
-  next_run = (case_is_null (&sort->run_end)
+  next_run = (sort->run_end == NULL
               || subcase_compare_3way (&sort->ordering, c,
-                                       &sort->ordering, &sort->run_end) < 0);
+                                       &sort->ordering, sort->run_end) < 0);
   pqueue_push (sort->pqueue, c, sort->run_id + (next_run ? 1 : 0));
 }
 
@@ -104,7 +104,7 @@ sort_casewriter_destroy (struct casewriter *writer UNUSED, void *sort_)
   merge_destroy (sort->merge);
   pqueue_destroy (sort->pqueue);
   casewriter_destroy (sort->run);
-  case_destroy (&sort->run_end);
+  case_unref (sort->run_end);
   free (sort);
 }
 
@@ -134,12 +134,12 @@ sort_casewriter_convert_to_reader (struct casewriter *writer, void *sort_)
 static void
 output_record (struct sort_writer *sort)
 {
-  struct ccase min_case;
+  struct ccase *min_case;
   casenumber min_run_id;
 
-  pqueue_pop (sort->pqueue, &min_case, &min_run_id);
+  min_case = pqueue_pop (sort->pqueue, &min_run_id);
 #if 0
-  printf ("\toutput: %f to run %d\n", case_num_idx (&min_case, 0), min_run_id);
+  printf ("\toutput: %f to run %d\n", case_num_idx (min_case, 0), min_run_id);
 #endif
 
   if (sort->run_id != min_run_id && sort->run != NULL)
@@ -153,10 +153,9 @@ output_record (struct sort_writer *sort)
       sort->run_id = min_run_id;
     }
 
-  case_destroy (&sort->run_end);
-  case_clone (&sort->run_end, &min_case);
-
-  casewriter_write (sort->run, &min_case);
+  case_unref (sort->run_end);
+  sort->run_end = case_ref (min_case);
+  casewriter_write (sort->run, min_case);
 }
 
 static struct casewriter_class sort_casewriter_class =
@@ -204,7 +203,7 @@ struct pqueue
 struct pqueue_record
   {
     casenumber id;
-    struct ccase c;
+    struct ccase *c;
     casenumber idx;
   };
 
@@ -238,10 +237,9 @@ pqueue_destroy (struct pqueue *pq)
     {
       while (!pqueue_is_empty (pq))
         {
-          struct ccase c;
           casenumber id;
-          pqueue_pop (pq, &c, &id);
-          case_destroy (&c);
+          struct ccase *c = pqueue_pop (pq, &id);
+          case_unref (c);
         }
       subcase_destroy (&pq->ordering);
       free (pq->records);
@@ -270,15 +268,15 @@ pqueue_push (struct pqueue *pq, struct ccase *c, casenumber id)
 
   r = &pq->records[pq->record_cnt++];
   r->id = id;
-  case_move (&r->c, c);
+  r->c = c;
   r->idx = pq->idx++;
 
   push_heap (pq->records, pq->record_cnt, sizeof *pq->records,
              compare_pqueue_records_minheap, pq);
 }
 
-static void
-pqueue_pop (struct pqueue *pq, struct ccase *c, casenumber *id)
+static struct ccase *
+pqueue_pop (struct pqueue *pq, casenumber *id)
 {
   struct pqueue_record *r;
 
@@ -289,7 +287,7 @@ pqueue_pop (struct pqueue *pq, struct ccase *c, casenumber *id)
 
   r = &pq->records[pq->record_cnt];
   *id = r->id;
-  case_move (c, &r->c);
+  return r->c;
 }
 
 /* Compares record-run tuples A and B on id, then on case data,
@@ -303,8 +301,7 @@ compare_pqueue_records_minheap (const void *a_, const void *b_,
   const struct pqueue *pq = pq_;
   int result = a->id < b->id ? -1 : a->id > b->id;
   if (result == 0)
-    result = subcase_compare_3way (&pq->ordering, &a->c,
-                                   &pq->ordering, &b->c);
+    result = subcase_compare_3way (&pq->ordering, a->c, &pq->ordering, b->c);
   if (result == 0)
     result = a->idx < b->idx ? -1 : a->idx > b->idx;
   return -result;
diff --git a/src/math/wilcoxon-sig.c b/src/math/wilcoxon-sig.c
new file mode 100644 (file)
index 0000000..d9a4bca
--- /dev/null
@@ -0,0 +1,156 @@
+/* PSPP - a program for statistical analysis.
+   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
+   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 <http://www.gnu.org/licenses/>. */
+
+/* Thanks to Rob van Son for writing the original version of this
+   file.  This version has been completely rewritten; only the
+   name of the function has been retained.  In the process of
+   rewriting, it was sped up from O(2**N) to O(N**3). */
+
+#include <config.h>
+#include "wilcoxon-sig.h"
+#include <assert.h>
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include "xalloc.h"
+
+/* For integers N and W, with 0 <= N < CHAR_BIT*sizeof(long),
+   calculates and returns the value of the function S(N,W),
+   defined as the number of subsets of 1, 2, 3, ..., N that sum
+   to at least W.  There are 2**N subsets of N items, so S(N,W)
+   is in the range 0...2**N.
+
+   There are a few trivial cases:
+
+           * For W <= 0, S(N,W) = 2**N.
+
+           * For W > N*(N+1)/2, S(N,W) = 0.
+
+           * S(1,1) = 1.
+
+   Notably, these trivial cases include all values of W for N = 1.
+
+   Now consider the remaining, nontrivial cases, that is, N > 1 and
+   1 <= W <= N*(N+1)/2.  In this case, apply the following identity:
+
+           S(N,W) = S(N-1, W) + S(N-1, W-N).
+
+   The first term on the right hand is the number of subsets that do
+   not include N that sum to at least W; the second term is the
+   number of subsets that do include N that sum to at least W.
+
+   Then we repeatedly apply the identity to the result, reducing the
+   value of N by 1 each time until we reach N=1.  Some expansions
+   yield trivial cases, e.g. if W - N <= 0 (in which case we add a
+   2**N term to the final result) or if W is greater than the new N.
+
+   Here is an example:
+
+   S(7,7) = S(6,7) + S(6,0)
+          = S(6,7) + 64
+
+          = (S(5,7) + S(5,1)) + 64
+
+          = (S(4,7) + S(4,2)) + (S(4,1) + S(4,0)) + 64
+          = S(4,7) + S(4,2) + S(4,1) + 80
+
+          = (S(3,7) + S(3,3)) + (S(3,2) + S(3,2)) + (S(3,1) + S(3,0)) + 80
+          = S(3,3) + 2*S(3,2) + S(3,1) + 88
+
+          = (S(2,3) + S(2,0)) + 2*(S(2,2) + S(2,0)) + (S(2,1) + S(2,0)) + 88
+          = S(2,3) + 2*S(2,2) + S(2,1) + 104
+
+          = (S(1,3) + S(1,1)) + 2*(S(1,2) + S(1,0)) + (S(1,1) + S(2,0)) + 104
+          = 2*S(1,1) + 112
+
+          = 114
+
+   This function runs in O(N*W) = O(N**3) time.  It seems very
+   likely that it can be made to run in O(N**2) time or perhaps
+   even better, but N is, practically speaking, quite small.
+   Plus, the return value may be as large as N**2, so N must not
+   be larger than 31 on 32-bit systems anyhow, and even 63**3 is
+   only 250,047.
+*/
+static unsigned long int
+count_sums_to_W (unsigned long int n, unsigned long int w)
+{
+  /* The array contain ints even though everything else is long,
+     but no element in the array can have a value bigger than N,
+     and using int will save some memory on 64-bit systems. */
+  unsigned long int total;
+  unsigned long int max;
+  int *array;
+
+  assert (n < CHAR_BIT * sizeof (unsigned long int));
+  if (n == 0)
+    return 0;
+  else if (w <= 0)
+    return 1 << n;
+  else if (w > n * (n + 1) / 2)
+    return 0;
+  else if (n == 1)
+    return 1;
+
+  array = xcalloc (sizeof *array, w + 1);
+  array[w] = 1;
+
+  max = w;
+  total = 0;
+  for (; n > 1; n--)
+    {
+      unsigned long int max_sum = n * (n + 1) / 2;
+      int i;
+
+      if (max_sum < max)
+        max = max_sum;
+
+      for (i = 1; i <= max; i++)
+        if (array[i] != 0)
+          {
+            int new_w = i - n;
+            if (new_w <= 0)
+               total += array[i] * (1 << (n - 1));
+            else
+              array[new_w] += array[i];
+          }
+    }
+  total += array[1];
+  free (array);
+  return total;
+}
+
+/* Returns the exact, two-tailed level of significance for the
+   Wilcoxon Matched-Pairs Signed-Ranks test, given sum of ranks
+   of positive (or negative samples) W and sample size N.
+
+   Returns -1 if the exact significance level cannot be
+   calculated because W is out of the supported range. */
+double
+LevelOfSignificanceWXMPSR (double w, long int n)
+{
+  unsigned long int max_w;
+
+  /* Limit N to valid range that won't cause integer overflow. */
+  if (n < 0 || n >= CHAR_BIT * sizeof (unsigned long int))
+    return -1;
+
+  max_w = n * (n + 1) / 2;
+  if (w < max_w / 2)
+    w = max_w - w;
+
+  return count_sums_to_W (n, ceil (w)) / (double) (1 << n) * 2;
+}
diff --git a/src/math/wilcoxon-sig.h b/src/math/wilcoxon-sig.h
new file mode 100644 (file)
index 0000000..07eba55
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef WX_MP_SR
+#define WX_MP_SR 1
+
+double LevelOfSignificanceWXMPSR(double w, long int n);
+
+#endif
index ef50285ea4ee1b8ba04624a37447daac433f16bb..67657f6247cc8ec731cf8154c4f45aa48d369003 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <data/file-name.h>
 #include <libpspp/str.h>
 
 #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)
         {
index 5ecf6695b3231122bc77cb05fa19844907b67bfc..765b529f4382c7d190414dbe643899c76ceb7d34 100644 (file)
@@ -1 +1,2 @@
 psppire
+*.ui
index e743fcf61dbfa7b8128c277b7c59e32dd4c49e9c..23ae5b0679077e3538df11e569277980ade964c4 100644 (file)
@@ -18,7 +18,6 @@
 #include <config.h>
 
 #include <gtk/gtk.h>
-#include <glade/glade.h>
 
 #include <libpspp/copyleft.h>
 #include <libpspp/version.h>
@@ -31,7 +30,7 @@ const static gchar *artists[] = { "Patrick Brunier", "Dondi Bogusky", NULL};
 void
 about_new (GtkMenuItem *m, GtkWindow *parent)
 {
-  GladeXML *xml = XML_NEW ("psppire.glade");
+  GtkBuilder *xml = builder_new ("psppire.ui");
 
   GtkWidget *about =  get_widget_assert (xml, "aboutdialog1");
 
index 895723a24b81e7572ba1db5637dba802f0bab78f..6440215a7667f684edceb3f647314b136d0efb1f 100644 (file)
@@ -9,6 +9,7 @@ src_ui_gui_psppire_CFLAGS = $(GTK_CFLAGS) $(GLADE_CFLAGS) -Wall \
 
 
 src_ui_gui_psppire_LDFLAGS = \
+       $(PSPPIRE_LDFLAGS) \
        $(PG_LDFLAGS)
 
 
@@ -60,26 +61,41 @@ src_ui_gui_psppire_LDADD = \
        src/libpspp-core.la \
        $(GTK_LIBS) \
        $(GLADE_LIBS) \
-       @LIBINTL@
+       @LIBINTL@ \
+       $(LIB_CLOSE)
 
 src_ui_gui_psppiredir = $(pkgdatadir)
 
-dist_src_ui_gui_psppire_DATA = \
-       $(top_srcdir)/src/ui/gui/data-editor.glade \
-       $(top_srcdir)/src/ui/gui/descriptives-dialog.glade \
-       $(top_srcdir)/src/ui/gui/examine.glade \
+nodist_src_ui_gui_psppire_DATA = \
+       $(top_builddir)/src/ui/gui/crosstabs.ui \
+       $(top_builddir)/src/ui/gui/examine.ui \
+       $(top_builddir)/src/ui/gui/frequencies.ui \
+       $(top_builddir)/src/ui/gui/message-dialog.ui \
+       $(top_builddir)/src/ui/gui/psppire.ui \
+       $(top_builddir)/src/ui/gui/oneway.ui \
+       $(top_builddir)/src/ui/gui/rank.ui \
+       $(top_builddir)/src/ui/gui/recode.ui \
+       $(top_builddir)/src/ui/gui/regression.ui \
+       $(top_builddir)/src/ui/gui/t-test.ui
+
+EXTRA_DIST += \
        $(top_srcdir)/src/ui/gui/crosstabs.glade \
+       $(top_srcdir)/src/ui/gui/examine.glade \
        $(top_srcdir)/src/ui/gui/frequencies.glade \
        $(top_srcdir)/src/ui/gui/message-dialog.glade \
-       $(top_srcdir)/src/ui/gui/oneway.glade \
-       $(top_srcdir)/src/ui/gui/output-viewer.glade \
        $(top_srcdir)/src/ui/gui/psppire.glade \
+       $(top_srcdir)/src/ui/gui/oneway.glade \
        $(top_srcdir)/src/ui/gui/rank.glade \
        $(top_srcdir)/src/ui/gui/recode.glade \
        $(top_srcdir)/src/ui/gui/regression.glade \
+       $(top_srcdir)/src/ui/gui/t-test.glade
+
+dist_src_ui_gui_psppire_DATA = \
+       $(top_srcdir)/src/ui/gui/data-editor.glade \
+       $(top_srcdir)/src/ui/gui/descriptives-dialog.glade \
+       $(top_srcdir)/src/ui/gui/output-viewer.glade \
        $(top_srcdir)/src/ui/gui/syntax-editor.glade \
        $(top_srcdir)/src/ui/gui/text-data-import.glade \
-       $(top_srcdir)/src/ui/gui/t-test.glade \
        $(top_srcdir)/src/ui/gui/psppicon.png \
        $(top_srcdir)/src/ui/gui/pspplogo.png \
        $(top_srcdir)/src/ui/gui/icons/value-labels.png \
@@ -209,8 +225,6 @@ nodist_src_ui_gui_psppire_SOURCES = \
        src/ui/gui/psppire-marshal.h
 
 
-
-
 yelp-check:
        @if ! yelp --version > /dev/null 2>&1 ; then \
                echo    ; \
@@ -230,8 +244,12 @@ src/ui/gui/psppire-marshal.c: src/ui/gui/marshaller-list
 src/ui/gui/psppire-marshal.h: src/ui/gui/marshaller-list
        glib-genmarshal --header --prefix=psppire_marshal $< > $@
 
+.glade.ui:
+       gtk-builder-convert $< $@
+
 EXTRA_DIST += src/ui/gui/OChangeLog\
        src/ui/gui/marshaller-list
 
 BUILT_SOURCES += src/ui/gui/psppire-marshal.c src/ui/gui/psppire-marshal.h
-CLEANFILES += src/ui/gui/psppire-marshal.c src/ui/gui/psppire-marshal.h
+CLEANFILES += src/ui/gui/psppire-marshal.c src/ui/gui/psppire-marshal.h \
+       $(nodist_src_ui_gui_psppire_DATA)
\ No newline at end of file
index 34c9957d4fea4ea659f56b7e02e9e91b090dc2df..49d143cb6c51f379df11ad5172c789fada53a7f6 100644 (file)
@@ -30,7 +30,6 @@
 #include "dialog-common.h"
 
 #include <gtk/gtk.h>
-#include <glade/glade.h>
 
 #include <gettext.h>
 
@@ -40,7 +39,7 @@
 
 struct comment_dialog
 {
-  GladeXML *xml;
+  GtkBuilder *xml;
   PsppireDict *dict;
 };
 
@@ -99,7 +98,7 @@ comments_dialog (GObject *o, gpointer data)
   PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
   struct comment_dialog cd;
 
-  GladeXML *xml = XML_NEW ("psppire.glade");
+  GtkBuilder *xml = builder_new ("psppire.ui");
 
   GtkWidget *dialog = get_widget_assert (xml, "comments-dialog");
   GtkWidget *textview = get_widget_assert (xml, "comments-textview1");
index 96ea6630885b08fedf74a9b42d655fa94e18f333..7269ab79750e76c3ed2cf5c7431045d5506545c3 100644 (file)
@@ -47,7 +47,7 @@ static void insert_source_row_into_text_view (GtkTreeIter iter,
 
 struct compute_dialog
 {
-  GladeXML *xml;  /* The xml that generated the widgets */
+  GtkBuilder *xml;  /* The xml that generated the widgets */
   PsppireDict *dict;
   gboolean use_type;
 };
@@ -113,7 +113,7 @@ erase_selection (GtkTextBuffer *buffer)
 static void
 on_keypad_button (PsppireKeypad *kp, const gchar *syntax, gpointer data)
 {
-  GladeXML *xml = data;
+  GtkBuilder *xml = data;
 
   GtkWidget *rhs = get_widget_assert (xml, "compute-textview1");
 
@@ -137,7 +137,7 @@ on_keypad_button (PsppireKeypad *kp, const gchar *syntax, gpointer data)
 static void
 erase (PsppireKeypad *kp, gpointer data)
 {
-  GladeXML *xml = data;
+  GtkBuilder *xml = data;
 
   GtkWidget *rhs = get_widget_assert (xml, "compute-textview1");
 
@@ -370,7 +370,7 @@ compute_dialog (GObject *o, gpointer data)
   PsppireVarStore *vs = NULL;
   struct compute_dialog scd;
 
-  GladeXML *xml = XML_NEW ("psppire.glade");
+  GtkBuilder *xml = builder_new ("psppire.ui");
 
   GtkWidget *dialog = get_widget_assert   (xml, "compute-variable-dialog");
 
index 8f16b5f6c02867662a102b696fc38a20202cce99..3611865e15de360bf1fa8d5688e14bbcbf547a20 100644 (file)
@@ -19,8 +19,6 @@
 
 
 #include <gtk/gtk.h>
-#include <glade/glade.h>
-
 
 void compute_dialog (GObject *o, gpointer data);
 
index 9654a27ccf90364a368cd89937999e9f8c39167b..a3498d1f6d72c4b70b72a46ccc6569721898c29e 100644 (file)
@@ -26,7 +26,7 @@
 #include <ui/gui/psppire-data-window.h>
 #include <ui/gui/dialog-common.h>
 #include <ui/gui/dict-display.h>
-#include <ui/gui/helper.h>
+#include "helper.h"
 #include <ui/gui/psppire-dialog.h>
 #include <ui/gui/psppire-var-store.h>
 #include <ui/gui/helper.h>
@@ -387,7 +387,7 @@ crosstabs_dialog (GObject *o, gpointer data)
   gint response;
   struct crosstabs_dialog cd;
 
-  GladeXML *xml = XML_NEW ("crosstabs.glade");
+  GtkBuilder *xml = builder_new ("crosstabs.ui");
 
   PsppireVarStore *vs = NULL;
 
index 33349b90ba71114336748d770772260214eb40d1..11da9814cfa462a37ab2960c5c16226f99b6b3ed 100644 (file)
@@ -19,7 +19,6 @@
 
 
 #include <gtk/gtk.h>
-#include <glade/glade.h>
 
 
 void crosstabs_dialog (GObject *o, gpointer data);
index 3c11a08aa477eea73f26f89f2f36ab737741934a..171d88cfc2f9f6def60a12b6fee571f22825bbce 100644 (file)
@@ -240,9 +240,7 @@ examine_dialog (GObject *o, gpointer data)
 
   struct examine_dialog ex_d;
 
-
-  GladeXML *xml = XML_NEW ("examine.glade");
-
+  GtkBuilder *xml = builder_new ("examine.ui");
 
   GtkWidget *dialog = get_widget_assert   (xml, "examine-dialog");
   GtkWidget *source = get_widget_assert   (xml, "treeview1");
index b8e70272e4802a8f9f6844ca7d40236ce6bdc1c4..d8e3fb6c259cab1560ff88645c1609689803d61e 100644 (file)
@@ -19,8 +19,6 @@
 
 
 #include <gtk/gtk.h>
-#include <glade/glade.h>
-
 
 void examine_dialog (GObject *o, gpointer data);
 
index ad9bf842efb447c9afa17927665a78da3bc9575e..130b25cfafe54db8f73eca358dada6da80f77b41 100644 (file)
@@ -37,7 +37,6 @@ which match particular strings */
 #include <libpspp/message.h>
 
 #include <gtk/gtk.h>
-#include <glade/glade.h>
 #include <stdlib.h>
 
 #include "xalloc.h"
@@ -52,7 +51,7 @@ which match particular strings */
 
 struct find_dialog
 {
-  GladeXML *xml;
+  GtkBuilder *xml;
   PsppireDict *dict;
   struct datasheet *data;
   PsppireDataWindow *de;
@@ -200,7 +199,7 @@ find_dialog (GObject *o, gpointer data)
   PsppireVarStore *vs ;
   PsppireDataStore *ds ;
 
-  fd.xml = XML_NEW ("psppire.glade");
+  fd.xml = builder_new ("psppire.ui");
   fd.de = de;
 
   find_button = gtk_button_new_from_stock  (GTK_STOCK_FIND);
index 978bfcd2eda7eb095ff729fa889ea4eb0760e295..37e301b88babb099490ed752a075e5e7f44da9f5 100644 (file)
@@ -311,7 +311,7 @@ frequencies_dialog (GObject *o, gpointer data)
 
   struct frequencies_dialog fd;
 
-  GladeXML *xml = XML_NEW ("frequencies.glade");
+  GtkBuilder *xml = builder_new ("frequencies.ui");
 
   GtkWidget *dialog = get_widget_assert   (xml, "frequencies-dialog");
   GtkWidget *source = get_widget_assert   (xml, "dict-treeview");
index 90990a414b29c98a51fa6d8285474553a1aec648..f4d44f35b35f2e565b49fcacd510856949d51504 100644 (file)
@@ -19,8 +19,6 @@
 
 
 #include <gtk/gtk.h>
-#include <glade/glade.h>
-
 
 void frequencies_dialog (GObject *o, gpointer data);
 
index 57db586511f27992fc7b569da1564f0c6c479434..9a523943b1c5686e639d4df34b56530d4f1b55a5 100644 (file)
@@ -24,7 +24,7 @@
 
 
 static void
-refresh (const PsppireDataWindow *de, GladeXML *xml)
+refresh (const PsppireDataWindow *de, GtkBuilder *xml)
 {
   PsppireDataStore *ds = NULL;
   casenumber case_count ;
@@ -43,7 +43,7 @@ void
 goto_case_dialog (GObject *o, gpointer data)
 {
   gint response;
-  GladeXML *xml = XML_NEW ("psppire.glade");
+  GtkBuilder *xml = builder_new ("psppire.ui");
   PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
 
   GtkWidget *dialog = get_widget_assert   (xml, "goto-case-dialog");
index 536ccb08e8edd86d0aa3d6ca6f5fbacc3997cd42..7b3da66d59969de80f0320405cf57db29d3ba62c 100644 (file)
@@ -19,8 +19,6 @@
 
 
 #include <gtk/gtk.h>
-#include <glade/glade.h>
-
 
 void goto_case_dialog (GObject *o, gpointer data);
 
index 12003e2ac23f8a48ec17a348c8aaca970921dd67..6a3a0f9e6ce0b83ee360f62ca9f790205084da7e 100644 (file)
@@ -34,6 +34,7 @@
 #include <data/casereader-provider.h>
 #include <libpspp/message.h>
 
+#include <gtk/gtkbuilder.h>
 #include <libpspp/i18n.h>
 
 #include <ctype.h>
@@ -102,14 +103,35 @@ text_to_value (const gchar *text, union value *v,
 }
 
 
+GtkBuilder *
+builder_new_real (const gchar *name)
+{
+  GtkBuilder *builder = gtk_builder_new ();
+
+  GError *err = NULL;
+  if ( ! gtk_builder_add_from_file (builder, name,  &err))
+    {
+      g_critical ("Couldnt open user interface  file %s: %s", name, err->message);
+      g_clear_error (&err);
+    }
+
+  return builder;
+}
+
+
+
 GtkWidget *
-get_widget_assert (GladeXML *xml, const gchar *name)
+get_widget_assert (gpointer x, const gchar *name)
 {
-  GtkWidget *w;
-  g_assert (xml);
+  GObject *obj = G_OBJECT (x);
+  GtkWidget *w = NULL;
   g_assert (name);
 
-  w = glade_xml_get_widget (xml, name);
+  if (GTK_IS_BUILDER (obj))
+    w = GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER (obj), name));
+
+  if (GLADE_IS_XML (obj))
+    w = glade_xml_get_widget (GLADE_XML (obj), name);
 
   if ( !w )
     g_critical ("Widget \"%s\" could not be found\n", name);
@@ -300,7 +322,6 @@ clone_list_store (const GtkListStore *src)
 
 
 
-
 void
 paste_syntax_in_new_window (const gchar *syntax)
 {
index 25ff0aa00c4cdccd60268efca6321eb4c045f1f2..d388ccb41821b132afaf5670647ea3dd961a0cd4 100644 (file)
@@ -47,7 +47,7 @@ gchar * value_to_text (union value v, struct fmt_spec format);
 gboolean text_to_value (const gchar *text, union value *v,
                       struct fmt_spec format);
 
-GtkWidget * get_widget_assert (GladeXML *xml, const gchar *name);
+GtkWidget * get_widget_assert (gpointer x, const gchar *name);
 
 /* Converts a string in the pspp locale to utf-8 */
 char * pspp_locale_to_utf8 (const gchar *text, gssize len, GError **err);
@@ -64,12 +64,9 @@ gboolean execute_syntax (struct getl_interface *sss);
    glade_xml_new (relocate(PKGDATADIR "/" FILE), NULL, NULL)
 
 
-void marshaller_VOID__INT_INT_INT (GClosure     *closure,
-                                  GValue       *return_value,
-                                  guint         n_param_values,
-                                  const GValue *param_values,
-                                  gpointer      invocation_hint,
-                                  gpointer      marshal_data);
+#define builder_new(NAME) builder_new_real (relocate (PKGDATADIR "/" NAME))
+
+GtkBuilder *builder_new_real (const gchar *name);
 
 
 /* Create a deep copy of SRC */
index d0f02dfaddef54f32b3c3fd9088fd8e7a7738fc0..866f8c6d91f1065762ba0a636291c255bd05c67a 100644 (file)
@@ -31,7 +31,6 @@
 
 
 #include <gtk/gtk.h>
-#include <glade/glade.h>
 #include <glib.h>
 
 #include "helper.h"
@@ -49,7 +48,7 @@ static GQueue *late_queue;
 
 static int error_cnt, warning_cnt, note_cnt;
 
-static GladeXML *message_xml;
+static GtkBuilder *message_xml;
 static GtkWidget *message_dialog;
 
 void
@@ -60,7 +59,7 @@ message_dialog_init (struct source_stream *ss)
   late_queue = g_queue_new ();
   error_cnt = warning_cnt = note_cnt = 0;
   msg_init (ss, enqueue_msg);
-  message_xml = XML_NEW ("message-dialog.glade");
+  message_xml = builder_new ("message-dialog.ui");
   message_dialog = get_widget_assert (message_xml, "message-dialog");
 }
 
index 45e888074cb586cc74f7de93fde4daedce62051a..d41b2760aa97630510ca82315ae96c1b1eb1f87c 100644 (file)
@@ -17,7 +17,6 @@
 
 
 #include <config.h>
-#include <glade/glade.h>
 #include <gtk/gtk.h>
 #include "oneway-anova-dialog.h"
 #include "psppire-dict.h"
@@ -121,6 +120,7 @@ refresh (struct oneway_anova_dialog *ow)
 }
 
 
+
 /* Pops up the dialog box */
 void
 oneway_anova_dialog (GObject *o, gpointer data)
@@ -130,43 +130,43 @@ oneway_anova_dialog (GObject *o, gpointer data)
 
   PsppireVarStore *vs = NULL;
 
-  GladeXML *xml = XML_NEW ("oneway.glade");
-
   struct oneway_anova_dialog ow;
 
+  GtkBuilder *builder = builder_new ("oneway.ui");
+
   GtkWidget *dict_view =
-    get_widget_assert (xml, "oneway-anova-treeview1");
+    get_widget_assert (builder, "oneway-anova-treeview1");
 
   GtkWidget *selector2 =
-    get_widget_assert (xml, "oneway-anova-selector2");
+    get_widget_assert (builder, "oneway-anova-selector2");
 
   GtkWidget *selector1 =
-    get_widget_assert (xml, "oneway-anova-selector1");
+    get_widget_assert (builder, "oneway-anova-selector1");
 
   GtkWidget *contrasts_button =
-    get_widget_assert (xml, "contrasts-button");
+    get_widget_assert (builder, "contrasts-button");
 
 
   g_signal_connect_swapped (contrasts_button, "clicked",
                    G_CALLBACK (run_contrasts_dialog), &ow);
 
 
-  ow.factor_entry = get_widget_assert (xml, "oneway-anova-entry");
+  ow.factor_entry = get_widget_assert (builder, "oneway-anova-entry");
   ow.vars_treeview =
-    get_widget_assert (xml, "oneway-anova-treeview2");
+    get_widget_assert (builder, "oneway-anova-treeview2");
 
   ow.descriptives =
-    GTK_TOGGLE_BUTTON (get_widget_assert (xml, "checkbutton1"));
+    GTK_TOGGLE_BUTTON (get_widget_assert (builder, "checkbutton1"));
 
   ow.homogeneity =
-    GTK_TOGGLE_BUTTON (get_widget_assert (xml, "checkbutton2"));
+    GTK_TOGGLE_BUTTON (get_widget_assert (builder, "checkbutton2"));
 
   g_object_get (de->data_editor, "var-store", &vs, NULL);
 
   ow.dict = vs->dict;
 
   ow.dialog =
-    GTK_WINDOW (get_widget_assert (xml, "oneway-anova-dialog"));
+    GTK_WINDOW (get_widget_assert (builder, "oneway-anova-dialog"));
 
   gtk_window_set_transient_for (ow.dialog, GTK_WINDOW (de));
 
@@ -202,16 +202,16 @@ oneway_anova_dialog (GObject *o, gpointer data)
 
   {
     struct contrasts_subdialog *cd = &ow.contrasts;
-    GtkEntry *entry = GTK_ENTRY (get_widget_assert (xml, "entry1"));
+    GtkEntry *entry = GTK_ENTRY (get_widget_assert (builder, "entry1"));
 
-    cd->acr = PSPPIRE_ACR (get_widget_assert (xml, "psppire-acr1"));
-    cd->contrasts_dialog = get_widget_assert (xml, "contrasts-dialog");
+    cd->acr = PSPPIRE_ACR (get_widget_assert (builder, "psppire-acr1"));
+    cd->contrasts_dialog = get_widget_assert (builder, "contrasts-dialog");
 
-    cd->next = get_widget_assert (xml, "next-button");
-    cd->prev = get_widget_assert (xml, "prev-button");
-    cd->ctotal = get_widget_assert (xml, "entry2");
+    cd->next = get_widget_assert (builder, "next-button");
+    cd->prev = get_widget_assert (builder, "prev-button");
+    cd->ctotal = get_widget_assert (builder, "entry2");
 
-    cd->stack_label = get_widget_assert (xml, "contrast-stack-label");
+    cd->stack_label = get_widget_assert (builder, "contrast-stack-label");
 
     /* Contrasts */
     ow.contrasts_array = g_array_new (FALSE, FALSE, sizeof (GtkListStore *));
@@ -253,7 +253,7 @@ oneway_anova_dialog (GObject *o, gpointer data)
 
   g_array_free (ow.contrasts_array, FALSE);
 
-  g_object_unref (xml);
+  g_object_unref (builder);
 }
 
 
index 00e227ecc922a465b939779000a31e69b359ea5e..735d4328c930b276f060f759e7024c687605de3b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 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
@@ -1607,16 +1607,9 @@ data_sheet_set_clip (PsppireSheet *sheet)
   writer = autopaging_writer_create (dict_get_next_value_idx (clip_dict));
   for (i = range.row0; i <= range.rowi ; ++i )
     {
-      struct ccase old;
-
-      if (psppire_data_store_get_case (ds, i, &old))
-        {
-          struct ccase new;
-
-          case_map_execute (map, &old, &new);
-          case_destroy (&old);
-          casewriter_write (writer, &new);
-        }
+      struct ccase *old = psppire_data_store_get_case (ds, i);
+      if (old != NULL)
+        casewriter_write (writer, case_map_execute (map, old));
       else
         casewriter_force_error (writer);
     }
@@ -1667,8 +1660,10 @@ clip_to_text (void)
   for (r = 0 ; r < case_cnt ; ++r )
     {
       int c;
-      struct ccase cc;
-      if ( !  casereader_peek (clip_datasheet, r, &cc))
+      struct ccase *cc;
+
+      cc = casereader_peek (clip_datasheet, r);
+      if (cc == NULL)
        {
          g_warning ("Clipboard seems to have inexplicably shrunk");
          break;
@@ -1677,7 +1672,7 @@ clip_to_text (void)
       for (c = 0 ; c < var_cnt ; ++c)
        {
          const struct variable *v = dict_get_var (clip_dict, c);
-         data_out_g_string (string, v, &cc);
+         data_out_g_string (string, v, cc);
          if ( c < val_cnt - 1 )
            g_string_append (string, "\t");
        }
@@ -1685,7 +1680,7 @@ clip_to_text (void)
       if ( r < case_cnt)
        g_string_append (string, "\n");
 
-      case_destroy (&cc);
+      case_unref (cc);
     }
 
   return string;
@@ -1710,8 +1705,8 @@ clip_to_html (void)
   for (r = 0 ; r < case_cnt ; ++r )
     {
       int c;
-      struct ccase cc;
-      if ( !  casereader_peek (clip_datasheet, r, &cc))
+      struct ccase *cc = casereader_peek (clip_datasheet, r);
+      if (cc == NULL)
        {
          g_warning ("Clipboard seems to have inexplicably shrunk");
          break;
@@ -1722,13 +1717,13 @@ clip_to_html (void)
        {
          const struct variable *v = dict_get_var (clip_dict, c);
          g_string_append (string, "<td>");
-         data_out_g_string (string, v, &cc);
+         data_out_g_string (string, v, cc);
          g_string_append (string, "</td>\n");
        }
 
       g_string_append (string, "</tr>\n");
 
-      case_destroy (&cc);
+      case_unref (cc);
     }
   g_string_append (string, "</table>\n");
 
index 91b96f64514da4a85ca0a696f652916f303f5b78..1bbd2bb8e517ddb48dd989a9734a88f9c46f1dc5 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2006, 2008  Free Software Foundation
+   Copyright (C) 2006, 2008, 2009  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
@@ -528,7 +528,7 @@ psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn)
 {
   gboolean result;
   gint val_cnt, v;
-  struct ccase cc;
+  struct ccase *cc;
   g_return_val_if_fail (ds, FALSE);
 
   val_cnt = datasheet_get_column_cnt (ds->datasheet) ;
@@ -537,9 +537,9 @@ psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn)
 
   g_return_val_if_fail (posn <= psppire_data_store_get_case_count (ds), FALSE);
 
-  case_create (&cc, val_cnt);
+  cc = case_create (val_cnt);
 
-  memset ( case_data_rw_idx (&cc, 0), 0, val_cnt * MAX_SHORT_STRING);
+  memset ( case_data_rw_idx (cc, 0), 0, val_cnt * MAX_SHORT_STRING);
 
   for (v = 0 ; v < psppire_dict_get_var_cnt (ds->dict) ; ++v)
     {
@@ -547,12 +547,12 @@ psppire_data_store_insert_new_case (PsppireDataStore *ds, casenumber posn)
       if ( var_is_alpha (pv))
        continue;
 
-      case_data_rw (&cc, pv)->f = SYSMIS;
+      case_data_rw (cc, pv)->f = SYSMIS;
     }
 
-  result = psppire_data_store_insert_case (ds, &cc, posn);
+  result = psppire_data_store_insert_case (ds, cc, posn);
 
-  case_destroy (&cc);
+  case_unref (cc);
 
   return result;
 }
@@ -834,18 +834,16 @@ get_column_justification (const PsppireSheetModel *model, gint col)
 \f
 
 
-/* Fills C with the CASENUMth case.
-   Returns true on success, false otherwise.
+/* Returns the CASENUMth case, or a null pointer on failure.
  */
-gboolean
+struct ccase *
 psppire_data_store_get_case (const PsppireDataStore *ds,
-                            casenumber casenum,
-                            struct ccase *c)
+                            casenumber casenum)
 {
   g_return_val_if_fail (ds, FALSE);
   g_return_val_if_fail (ds->datasheet, FALSE);
 
-  return datasheet_get_row (ds->datasheet, casenum, c);
+  return datasheet_get_row (ds->datasheet, casenum);
 }
 
 
@@ -876,14 +874,13 @@ psppire_data_store_insert_case (PsppireDataStore *ds,
                                struct ccase *cc,
                                casenumber posn)
 {
-  struct ccase tmp;
   bool result ;
 
   g_return_val_if_fail (ds, FALSE);
   g_return_val_if_fail (ds->datasheet, FALSE);
 
-  case_clone (&tmp, cc);
-  result = datasheet_insert_rows (ds->datasheet, posn, &tmp, 1);
+  case_ref (cc);
+  result = datasheet_insert_rows (ds->datasheet, posn, &cc, 1);
 
   if ( result )
     {
index 44b11725babd667a32bb561a00bc3c6e896f78a7..5ffd85d68e458137b2b7c2cc25177fc3ce38b42b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2006  Free Software Foundation
+   Copyright (C) 2006, 2009  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
@@ -122,9 +122,8 @@ size_t psppire_data_store_get_value_count (const PsppireDataStore *ds);
 
 \f
 
-gboolean psppire_data_store_get_case (const PsppireDataStore *ds,
-                                     casenumber casenum,
-                                     struct ccase *c);
+struct ccase *psppire_data_store_get_case (const PsppireDataStore *ds,
+                                           casenumber casenum);
 
 
 
index 24d9089698fddeeb2ca098b1d146c844ecec413d..84f9e5de489459a86c702c912a32d7c882a3fc17 100644 (file)
 
 #include <gtk/gtk.h>
 #include <gtk/gtksignal.h>
+#include <gtk/gtkbuildable.h>
 #include "psppire-dialog.h"
 #include "psppire-buttonbox.h"
 #include "psppire-selector.h"
+#include <string.h>
 
 static void psppire_dialog_class_init          (PsppireDialogClass *);
 static void psppire_dialog_init                (PsppireDialog      *);
@@ -34,6 +36,9 @@ enum  {DIALOG_REFRESH,
 static guint signals [n_SIGNALS];
 
 
+static void psppire_dialog_buildable_init (GtkBuildableIface *iface);
+
+
 GType
 psppire_dialog_get_type (void)
 {
@@ -54,8 +59,20 @@ psppire_dialog_get_type (void)
        (GInstanceInitFunc) psppire_dialog_init,
       };
 
+      static const GInterfaceInfo buildable_info =
+      {
+       (GInterfaceInitFunc) psppire_dialog_buildable_init,
+       NULL,
+       NULL
+      };
+
       dialog_type = g_type_register_static (GTK_TYPE_WINDOW,
                                            "PsppireDialog", &dialog_info, 0);
+
+      g_type_add_interface_static (dialog_type,
+                                  GTK_TYPE_BUILDABLE,
+                                  &buildable_info);
+
     }
 
   return dialog_type;
@@ -475,3 +492,26 @@ psppire_dialog_set_valid_predicate (PsppireDialog *dialog,
 }
 
 
+
+
+
+static GObject *
+get_internal_child    (GtkBuildable *buildable,
+                      GtkBuilder *builder,
+                      const gchar *childname)
+{
+  PsppireDialog *dialog = PSPPIRE_DIALOG (buildable);
+
+  if ( 0 == strcmp (childname, "hbox"))
+    return G_OBJECT (dialog->box);
+
+  return NULL;
+}
+
+
+
+static void
+psppire_dialog_buildable_init (GtkBuildableIface *iface)
+{
+  iface->get_internal_child = get_internal_child;
+}
index 62117a01bc0bbfc779476da08d3117a0913d59ad..bdd5ad5332f4062d4b0bf6927a42ea2b57223d30 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2004, 2005, 2006  Free Software Foundation
+   Copyright (C) 2004, 2005, 2006, 2009  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
@@ -20,7 +20,6 @@
 #include <assert.h>
 #include <libintl.h>
 #include <gsl/gsl_errno.h>
-#include <signal.h>
 
 #include <argp.h>
 #include <ui/command-line.h>
@@ -80,6 +79,10 @@ replace_casereader (struct casereader *s)
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
+
+const char * output_file_name (void);
+
+
 void
 initialize (struct command_line_processor *clp, int argc, char **argv)
 {
@@ -121,20 +124,29 @@ 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);
+
+    outp_configure_driver_line (ds_ss (&config_string));
+
+    unlink (filename);
 
-  unlink (OUTPUT_FILE_NAME);
+    ds_destroy (&config_string);
+  }
 
   journal_enable ();
   textdomain (PACKAGE);
 
-  /* Ignore alarm clock signals */
-  signal (SIGALRM, SIG_IGN);
-
   the_data_window = psppire_data_window_new ();
 
   command_line_processor_replace_aux (clp, &post_init_argp, the_source_stream);
@@ -295,3 +307,17 @@ parse_non_options (int key, char *arg, struct argp_state *state)
 
 
 const struct argp non_option_argp = {NULL, parse_non_options, 0, 0, 0, 0, 0};
+
+
+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;
+}
index 16d66e8abfe54cd0eae448330512b7eac9cd7dae..473d530473894da5915f747c82e838707630b2bc 100644 (file)
                     <property name="left_margin">3</property>
                     <property name="cursor_visible">False</property>
                     <property name="accepts_tab">False</property>
-                    <property name="text" translatable="yes">
-
-
-
-
-
-
-
-
-
-</property>
                   </widget>
                 </child>
               </widget>
index 307e37331038137e3e747fe02fd4e918aaf4e4d0..8ea25a1d9e8e5f9f93f39619ad39f37409bdce84 100644 (file)
@@ -224,73 +224,73 @@ rank_dialog (GObject *o, gpointer data)
 
   struct rank_dialog rd;
 
-  GladeXML *xml = XML_NEW ("rank.glade");
+  GtkBuilder * builder = builder_new ("rank.ui");
 
-  GtkWidget *vars = get_widget_assert   (xml, "dict-treeview");
-  GtkWidget *selector1 = get_widget_assert (xml, "psppire-selector1");
-  GtkWidget *selector2 = get_widget_assert (xml, "psppire-selector2");
+  GtkWidget *vars = get_widget_assert   (builder, "dict-treeview");
+  GtkWidget *selector1 = get_widget_assert (builder, "psppire-selector1");
+  GtkWidget *selector2 = get_widget_assert (builder, "psppire-selector2");
 
 
-  GtkWidget *types_button = get_widget_assert (xml, "button1");
-  GtkWidget *ties_button = get_widget_assert (xml, "button2");
+  GtkWidget *types_button = get_widget_assert (builder, "button1");
+  GtkWidget *ties_button = get_widget_assert (builder, "button2");
 
   PsppireVarStore *vs = NULL;
 
   g_object_get (de->data_editor, "var-store", &vs, NULL);
 
   rd.dict = vs->dict;
-  rd.rank_vars =   get_widget_assert (xml, "variables-treeview");
-  rd.group_vars =  get_widget_assert (xml, "group-vars-treeview");
-  rd.dialog = get_widget_assert   (xml, "rank-dialog");
+  rd.rank_vars =   get_widget_assert (builder, "variables-treeview");
+  rd.group_vars =  get_widget_assert (builder, "group-vars-treeview");
+  rd.dialog = get_widget_assert   (builder, "rank-dialog");
   rd.ascending_togglebutton =
-    GTK_TOGGLE_BUTTON (get_widget_assert (xml, "radiobutton1"));
+    GTK_TOGGLE_BUTTON (get_widget_assert (builder, "radiobutton1"));
 
   rd.summary_togglebutton =
-    GTK_TOGGLE_BUTTON (get_widget_assert (xml, "summary-checkbutton"));
+    GTK_TOGGLE_BUTTON (get_widget_assert (builder, "summary-checkbutton"));
 
-  rd.types_dialog = get_widget_assert (xml, "rank-types-dialog");
+  rd.types_dialog = get_widget_assert (builder, "rank-types-dialog");
 
 
-  rd.ntiles_entry  = get_widget_assert (xml, "ntiles-entry");
+  rd.ntiles_entry  = get_widget_assert (builder, "ntiles-entry");
 
   rd.func_button[RANK]    =
-    GTK_TOGGLE_BUTTON (get_widget_assert (xml, "rank-checkbutton"));
+    GTK_TOGGLE_BUTTON (get_widget_assert (builder, "rank-checkbutton"));
 
   rd.func_button[SAVAGE]  =
-    GTK_TOGGLE_BUTTON (get_widget_assert (xml, "savage-checkbutton"));
+    GTK_TOGGLE_BUTTON (get_widget_assert (builder, "savage-checkbutton"));
 
   rd.func_button[RFRACTION] =
-    GTK_TOGGLE_BUTTON (get_widget_assert (xml, "rfrac-checkbutton"));
+    GTK_TOGGLE_BUTTON (get_widget_assert (builder, "rfrac-checkbutton"));
 
   rd.func_button[PERCENT] =
-    GTK_TOGGLE_BUTTON (get_widget_assert (xml, "percent-checkbutton"));
+    GTK_TOGGLE_BUTTON (get_widget_assert (builder, "percent-checkbutton"));
 
   rd.func_button[N]       =
-    GTK_TOGGLE_BUTTON (get_widget_assert (xml, "sum-checkbutton"));
+    GTK_TOGGLE_BUTTON (get_widget_assert (builder, "sum-checkbutton"));
 
   rd.func_button[NTILES] =
-    GTK_TOGGLE_BUTTON (get_widget_assert (xml, "ntiles-checkbutton"));
+    GTK_TOGGLE_BUTTON (get_widget_assert (builder, "ntiles-checkbutton"));
 
   rd.func_button[PROPORTION] =
-    GTK_TOGGLE_BUTTON (get_widget_assert (xml, "prop-checkbutton"));
+    GTK_TOGGLE_BUTTON (get_widget_assert (builder, "prop-checkbutton"));
 
   rd.func_button[NORMAL] =
-    GTK_TOGGLE_BUTTON (get_widget_assert (xml, "normal-checkbutton"));
+    GTK_TOGGLE_BUTTON (get_widget_assert (builder, "normal-checkbutton"));
 
-  rd.formula_box = get_widget_assert (xml, "formula-frame");
+  rd.formula_box = get_widget_assert (builder, "formula-frame");
 
-  rd.blom = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "blom-button"));
-  rd.tukey = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "tukey-button"));
-  rd.rankit = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "rankit-button"));
-  rd.vw = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "vw-button"));
+  rd.blom = GTK_TOGGLE_BUTTON (get_widget_assert (builder, "blom-button"));
+  rd.tukey = GTK_TOGGLE_BUTTON (get_widget_assert (builder, "tukey-button"));
+  rd.rankit = GTK_TOGGLE_BUTTON (get_widget_assert (builder, "rankit-button"));
+  rd.vw = GTK_TOGGLE_BUTTON (get_widget_assert (builder, "vw-button"));
 
   /* Ties dialog */
-  rd.ties_dialog = PSPPIRE_DIALOG (get_widget_assert (xml, "ties-dialog"));
+  rd.ties_dialog = PSPPIRE_DIALOG (get_widget_assert (builder, "ties-dialog"));
 
-  rd.mean = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "mean-button"));
-  rd.low = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "low-button"));
-  rd.high = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "high-button"));
-  rd.condense = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "condense-button"));
+  rd.mean = GTK_TOGGLE_BUTTON (get_widget_assert (builder, "mean-button"));
+  rd.low = GTK_TOGGLE_BUTTON (get_widget_assert (builder, "low-button"));
+  rd.high = GTK_TOGGLE_BUTTON (get_widget_assert (builder, "high-button"));
+  rd.condense = GTK_TOGGLE_BUTTON (get_widget_assert (builder, "condense-button"));
 
   g_signal_connect_swapped (rd.func_button[PROPORTION], "toggled",
                            G_CALLBACK (set_sensitivity),
@@ -367,7 +367,7 @@ rank_dialog (GObject *o, gpointer data)
       break;
     }
 
-  g_object_unref (xml);
+  g_object_unref (builder);
 }
 
 
index a2ddace6e50cb4c8f8a5ec1c86d46776b791f0ba..8a5064f5c7e58bbb5c7d9071a4a3cfab5be82447 100644 (file)
@@ -19,8 +19,6 @@
 
 
 #include <gtk/gtk.h>
-#include <glade/glade.h>
-
 
 void rank_dialog (GObject *o, gpointer data);
 
index 642dae02d4a01283276c86356618b79cf7689603..859737f63e7d4d7895c1347f2a585c60d28cb5ab 100644 (file)
@@ -842,28 +842,27 @@ recode_dialog (PsppireDataWindow *de, gboolean diff)
 
   struct recode_dialog rd;
 
-  GladeXML *xml = XML_NEW ("recode.glade");
+  GtkBuilder *builder = builder_new ("recode.ui");
 
+  GtkWidget *selector = get_widget_assert (builder, "psppire-selector1");
 
-  GtkWidget *selector = get_widget_assert (xml, "psppire-selector1");
+  GtkWidget *oldandnew = get_widget_assert (builder, "button1");
 
-  GtkWidget *oldandnew = get_widget_assert (xml, "button1");
 
-
-  GtkWidget *output_variable_box = get_widget_assert (xml,"frame4");
+  GtkWidget *output_variable_box = get_widget_assert (builder,"frame4");
 
 
   PsppireVarStore *vs = NULL;
 
   g_object_get (de->data_editor, "var-store", &vs, NULL);
 
-  rd.change_button = get_widget_assert (xml, "change-button");
+  rd.change_button = get_widget_assert (builder, "change-button");
 
-  rd.dialog = get_widget_assert   (xml, "recode-dialog");
-  rd.dict_treeview = get_widget_assert (xml, "treeview1");
-  rd.variable_treeview =   get_widget_assert (xml, "treeview2");
-  rd.new_name_entry = get_widget_assert (xml, "dest-name-entry");
-  rd.new_label_entry = get_widget_assert (xml, "dest-label-entry");
+  rd.dialog = get_widget_assert   (builder, "recode-dialog");
+  rd.dict_treeview = get_widget_assert (builder, "treeview1");
+  rd.variable_treeview =   get_widget_assert (builder, "treeview2");
+  rd.new_name_entry = get_widget_assert (builder, "dest-name-entry");
+  rd.new_label_entry = get_widget_assert (builder, "dest-label-entry");
 
   rd.dict = vs->dict;
 
@@ -963,40 +962,40 @@ recode_dialog (PsppireDataWindow *de, gboolean diff)
 
   /* Set up the Old & New Values subdialog */
   {
-    rd.string_button = get_widget_assert (xml, "checkbutton1");
-    rd.width_entry   = get_widget_assert (xml, "spinbutton1");
+    rd.string_button = get_widget_assert (builder, "checkbutton1");
+    rd.width_entry   = get_widget_assert (builder, "spinbutton1");
 
-    rd.convert_button           = get_widget_assert (xml, "checkbutton2");
+    rd.convert_button           = get_widget_assert (builder, "checkbutton2");
 
-    rd.ov_range_lower_entry = get_widget_assert (xml, "entry5");
-    rd.ov_range_upper_entry  = get_widget_assert (xml, "entry3");
-    rd.ov_low_up_entry       = get_widget_assert (xml, "entry6");
-    rd.ov_high_down_entry    = get_widget_assert (xml, "entry7");
+    rd.ov_range_lower_entry = get_widget_assert (builder, "entry5");
+    rd.ov_range_upper_entry  = get_widget_assert (builder, "entry3");
+    rd.ov_low_up_entry       = get_widget_assert (builder, "entry6");
+    rd.ov_high_down_entry    = get_widget_assert (builder, "entry7");
 
-    rd.new_value_entry = get_widget_assert (xml, "entry1");
-    rd.ov_value_entry  = get_widget_assert (xml, "entry2");
+    rd.new_value_entry = get_widget_assert (builder, "entry1");
+    rd.ov_value_entry  = get_widget_assert (builder, "entry2");
 
-    rd.toggle[BUTTON_NEW_VALUE]  = get_widget_assert (xml, "radiobutton1");
-    rd.toggle[BUTTON_NEW_SYSMIS] = get_widget_assert (xml, "radiobutton2");
-    rd.toggle[BUTTON_NEW_COPY]   = get_widget_assert (xml, "radiobutton3");
-    rd.toggle[BUTTON_OLD_VALUE]  = get_widget_assert (xml, "radiobutton4");
-    rd.toggle[BUTTON_OLD_SYSMIS] = get_widget_assert (xml, "radiobutton6");
-    rd.toggle[BUTTON_OLD_MISSING]= get_widget_assert (xml, "radiobutton7");
-    rd.toggle[BUTTON_OLD_RANGE]  = get_widget_assert (xml, "radiobutton8");
-    rd.toggle[BUTTON_OLD_LOW_UP] = get_widget_assert (xml, "radiobutton10");
-    rd.toggle[BUTTON_OLD_HIGH_DOWN] = get_widget_assert (xml, "radiobutton5");
-    rd.toggle[BUTTON_OLD_ELSE]   = get_widget_assert (xml, "radiobutton11");
+    rd.toggle[BUTTON_NEW_VALUE]  = get_widget_assert (builder, "radiobutton1");
+    rd.toggle[BUTTON_NEW_SYSMIS] = get_widget_assert (builder, "radiobutton2");
+    rd.toggle[BUTTON_NEW_COPY]   = get_widget_assert (builder, "radiobutton3");
+    rd.toggle[BUTTON_OLD_VALUE]  = get_widget_assert (builder, "radiobutton4");
+    rd.toggle[BUTTON_OLD_SYSMIS] = get_widget_assert (builder, "radiobutton6");
+    rd.toggle[BUTTON_OLD_MISSING]= get_widget_assert (builder, "radiobutton7");
+    rd.toggle[BUTTON_OLD_RANGE]  = get_widget_assert (builder, "radiobutton8");
+    rd.toggle[BUTTON_OLD_LOW_UP] = get_widget_assert (builder, "radiobutton10");
+    rd.toggle[BUTTON_OLD_HIGH_DOWN] = get_widget_assert (builder, "radiobutton5");
+    rd.toggle[BUTTON_OLD_ELSE]   = get_widget_assert (builder, "radiobutton11");
 
-    rd.new_copy_label = get_widget_assert (xml, "label3");
-    rd.strings_box    = get_widget_assert (xml, "table3");
+    rd.new_copy_label = get_widget_assert (builder, "label3");
+    rd.strings_box    = get_widget_assert (builder, "table3");
 
     rd.old_and_new_dialog =
-      PSPPIRE_DIALOG (get_widget_assert (xml, "old-new-values-dialog"));
+      PSPPIRE_DIALOG (get_widget_assert (builder, "old-new-values-dialog"));
 
     gtk_window_set_transient_for (GTK_WINDOW (rd.old_and_new_dialog),
                                  GTK_WINDOW (de));
 
-    rd.acr = PSPPIRE_ACR (get_widget_assert (xml, "psppire-acr1"));
+    rd.acr = PSPPIRE_ACR (get_widget_assert (builder, "psppire-acr1"));
 
     g_signal_connect_swapped (rd.toggle[BUTTON_NEW_VALUE], "toggled",
                      G_CALLBACK (set_acr), &rd);
@@ -1047,11 +1046,11 @@ recode_dialog (PsppireDataWindow *de, gboolean diff)
 
     g_signal_connect (rd.toggle[BUTTON_OLD_RANGE], "toggled",
                      G_CALLBACK (toggle_sensitivity),
-                     get_widget_assert (xml, "entry3"));
+                     get_widget_assert (builder, "entry3"));
 
     g_signal_connect (rd.toggle[BUTTON_OLD_RANGE], "toggled",
                      G_CALLBACK (toggle_sensitivity),
-                     get_widget_assert (xml, "entry5"));
+                     get_widget_assert (builder, "entry5"));
 
     g_signal_connect (rd.toggle[BUTTON_OLD_LOW_UP], "toggled",
                      G_CALLBACK (toggle_sensitivity), rd.ov_low_up_entry);
@@ -1108,7 +1107,7 @@ recode_dialog (PsppireDataWindow *de, gboolean diff)
   gtk_list_store_clear (GTK_LIST_STORE (rd.value_map));
   g_object_unref (rd.value_map);
 
-  g_object_unref (xml);
+  g_object_unref (builder);
 }
 
 /* Initialise VAL to reflect the current status of RD */
index b0c11b0798dc8d591594055f7b5cb8fdd14c169b..2d8aca3ebc6a5d074e3a329211d25c530df83f2e 100644 (file)
@@ -225,9 +225,8 @@ regression_dialog (GObject *o, gpointer data)
   gint response;
   struct regression_dialog rd;
 
-  GladeXML *xml = XML_NEW ("regression.glade");
+  GtkBuilder *xml = builder_new ("regression.ui");
   PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
-
   PsppireVarStore *vs;
 
   GtkWidget *dialog = get_widget_assert   (xml, "regression-dialog");
index ca79ba350c9f34f89ac155f37b368656f1212a43..d34a61c9f059a496999d873d85d2b9ce8e057383 100644 (file)
@@ -19,8 +19,6 @@
 
 
 #include <gtk/gtk.h>
-#include <glade/glade.h>
-
 
 void regression_dialog (GObject *o, gpointer data);
 
index 58b2879d07fe79cfdfa7d774d3b833fd22d11bb3..d953308a09fbe8b27c92c84ff54c045e8eac4e27 100644 (file)
@@ -18,7 +18,6 @@
 
 #include "select-cases-dialog.h"
 #include <gtk/gtk.h>
-#include <glade/glade.h>
 #include "helper.h"
 #include "psppire-dialog.h"
 #include "psppire-data-window.h"
@@ -42,7 +41,7 @@
 struct select_cases_dialog
 {
   /* The XML that created the dialog */
-  GladeXML *xml;
+  GtkBuilder *xml;
 
   GtkWidget *spinbutton ;
   GtkWidget *spinbutton1 ;
@@ -247,7 +246,7 @@ select_cases_dialog (GObject *o, gpointer data)
   GtkWidget *button_range;
   GtkWidget *button_sample;
 
-  scd.xml = XML_NEW ("psppire.glade");
+  scd.xml = builder_new ("psppire.ui");
 
   g_object_get (de->data_editor, "data-store", &scd.data_store, NULL);
 
index 533992e0c5d191ecc8ae953de08e2beb698e77f3..b585b096fc43c966a342b8b692be714d1939894d 100644 (file)
@@ -19,7 +19,6 @@
 
 
 #include <gtk/gtk.h>
-#include <glade/glade.h>
 
 
 void select_cases_dialog (GObject *o, gpointer data);
index 6da083be724ef166b6a89f86259f39083e19d03b..d9c665e69a8db988df983919d7ea6d651cc9c9ea 100644 (file)
@@ -95,7 +95,7 @@ sort_cases_dialog (GObject *o, gpointer data)
 
   struct sort_cases_dialog scd;
 
-  GladeXML *xml = XML_NEW ("psppire.glade");
+  GtkBuilder *xml = builder_new ("psppire.ui");
 
   GtkWidget *dialog = get_widget_assert   (xml, "sort-cases-dialog");
 
index badcdd60f81af57130e53701883bd99e245b6931..000d2c00810634bbecc07a921b8dbca26afe7477 100644 (file)
@@ -19,8 +19,6 @@
 
 
 #include <gtk/gtk.h>
-#include <glade/glade.h>
-
 
 void sort_cases_dialog (GObject *o, gpointer data);
 
index c44d5591cd9c08e20f88cd2bd90bf63658c09318..8708b33f05df2d5613cc0b514d4cf0150e055156 100644 (file)
@@ -27,7 +27,6 @@
 #include <data/dictionary.h>
 
 #include <gtk/gtk.h>
-#include <glade/glade.h>
 
 
 #include "dialog-common.h"
@@ -39,7 +38,7 @@
 struct split_file_dialog
 {
   /* The XML that created the dialog */
-  GladeXML *xml;
+  GtkBuilder *xml;
 
   /* The dictionary to which this dialog pertains */
   PsppireDict *dict;
@@ -109,7 +108,7 @@ static void
 on_off_toggled (GtkToggleButton *togglebutton,
                gpointer         user_data)
 {
-  GladeXML *xml = user_data;
+  GtkBuilder *xml = user_data;
   GtkWidget *dest =   get_widget_assert (xml, "split-file-grouping-vars");
   GtkWidget *selector = get_widget_assert (xml, "split-file-selector");
   GtkWidget *source = get_widget_assert (xml, "split-file-dict-treeview");
@@ -177,7 +176,7 @@ split_file_dialog (GObject *o, gpointer data)
   GtkWidget *selector ;
   GtkWidget *on_off   ;
 
-  sfd.xml = XML_NEW ("psppire.glade");
+  sfd.xml = builder_new ("psppire.ui");
 
   dialog = get_widget_assert   (sfd.xml, "split-file-dialog");
   source = get_widget_assert   (sfd.xml, "split-file-dict-treeview");
index 4ceab4d8e8cfa91840c359f866d97e5a62460ae1..392867adbb606acd5c62abad6ce6a58286807f13 100644 (file)
@@ -17,7 +17,6 @@
 
 
 #include <config.h>
-#include <glade/glade.h>
 #include <gtk/gtk.h>
 #include "t-test-independent-samples-dialog.h"
 #include "psppire-dict.h"
@@ -91,7 +90,7 @@ tt_groups_dialog_destroy (struct tt_groups_dialog *grps)
 }
 
 static struct tt_groups_dialog *
-tt_groups_dialog_create (GladeXML *xml, GtkWindow *parent)
+tt_groups_dialog_create (GtkBuilder *xml, GtkWindow *parent)
 {
   struct tt_groups_dialog *grps = xmalloc (sizeof (*grps));
 
@@ -127,7 +126,7 @@ tt_groups_dialog_create (GladeXML *xml, GtkWindow *parent)
 
 struct tt_indep_samples_dialog
 {
-  GladeXML *xml;  /* The xml that generated the widgets */
+  GtkBuilder *xml;  /* The xml that generated the widgets */
   GtkWidget *dialog;
   PsppireDict *dict;
   GtkWidget *define_groups_button;
@@ -396,7 +395,7 @@ t_test_independent_samples_dialog (GObject *o, gpointer data)
 
   PsppireVarStore *vs = NULL;
 
-  GladeXML *xml = XML_NEW ("t-test.glade");
+  GtkBuilder *xml = builder_new ("t-test.ui");
 
   GtkWidget *dict_view =
     get_widget_assert (xml, "indep-samples-t-test-treeview1");
index 985845015f56db5473cbd4d035a385666b0d2d05..3cdc91c32721f4780684f2966c5b896ecaae6ef3 100644 (file)
@@ -17,7 +17,6 @@
 
 
 #include <config.h>
-#include <glade/glade.h>
 #include <gtk/gtk.h>
 #include "t-test-one-sample.h"
 #include "psppire-dict.h"
@@ -127,7 +126,7 @@ t_test_one_sample_dialog (GObject *o, gpointer data)
 
   PsppireVarStore *vs = NULL;
 
-  GladeXML *xml = XML_NEW ("t-test.glade");
+  GtkBuilder *xml = builder_new ("t-test.ui");
 
   GtkWidget *dict_view =
     get_widget_assert (xml, "one-sample-t-test-treeview2");
index eaf7c43f00da785ea8cd30269343a35008a85b9d..ed8ac042daaf7e3e420eb739dcfd0e32a6ef24a1 100644 (file)
@@ -52,7 +52,7 @@ struct tt_options_dialog
 };
 
 struct tt_options_dialog *
-tt_options_dialog_create (GladeXML *xml, GtkWindow *parent)
+tt_options_dialog_create (GtkBuilder *xml, GtkWindow *parent)
 {
   struct tt_options_dialog *tto = xmalloc (sizeof (*tto));
 
index fdb2d87cf6e744db157e63c26747c1029348b5bf..e80ef44496c5e21e08e0eabd1cafc90a047694ef 100644 (file)
@@ -24,7 +24,7 @@ struct tt_options_dialog;
 
 void tt_options_dialog_run (struct tt_options_dialog *);
 
-struct tt_options_dialog * tt_options_dialog_create (GladeXML *, GtkWindow *);
+struct tt_options_dialog * tt_options_dialog_create (GtkBuilder *, GtkWindow *);
 
 void tt_options_dialog_destroy (struct tt_options_dialog *);
 
index 58b68b2ff2f652d387f34d1d7394e33e20f8437f..ca1d776a7294f6bed0b91060e4be8f7878ef4b2c 100644 (file)
@@ -17,7 +17,6 @@
 
 #include <config.h>
 #include <gtk/gtk.h>
-#include <glade/glade.h>
 #include <language/syntax-string-source.h>
 
 #include "psppire-data-window.h"
@@ -185,7 +184,7 @@ t_test_paired_samples_dialog (GObject *o, gpointer data)
 
   PsppireVarStore *vs = NULL;
 
-  GladeXML *xml = XML_NEW ("t-test.glade");
+  GtkBuilder *xml = builder_new ("t-test.ui");
 
   GtkWidget *dict_view =
     get_widget_assert (xml, "paired-samples-t-test-treeview1");
index 9e8c18f44e2ac601bb9a56bca1ab245b78dce963..09756d3738919bc40f2f314b3d4d924a7a287499 100644 (file)
@@ -28,7 +28,6 @@
 #include "dialog-common.h"
 
 #include <gtk/gtk.h>
-#include <glade/glade.h>
 
 #include <gettext.h>
 
 #include "psppire-var-store.h"
 
 
-static gchar * generate_syntax (PsppireDict *dict, GladeXML *xml);
+static gchar * generate_syntax (PsppireDict *dict, GtkBuilder *xml);
 
 static void
 refresh (PsppireDialog *dialog, gpointer data)
 {
-  GladeXML *xml = data;
+  GtkBuilder *xml = data;
   GtkWidget *dest = get_widget_assert (xml, "variables-treeview");
   GtkWidget *entry = get_widget_assert (xml, "new-name-entry");
   GtkTreeModel *dmodel = gtk_tree_view_get_model (GTK_TREE_VIEW (dest));
@@ -57,7 +56,7 @@ refresh (PsppireDialog *dialog, gpointer data)
 static gboolean
 dialog_state_valid (gpointer data)
 {
-  GladeXML *xml = data;
+  GtkBuilder *xml = data;
 
   GtkWidget *tv = get_widget_assert (xml, "variables-treeview");
   GtkWidget *entry = get_widget_assert (xml, "new-name-entry");
@@ -82,7 +81,7 @@ transpose_dialog (GObject *o, gpointer data)
   gint response ;
   PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
 
-  GladeXML *xml = XML_NEW ("psppire.glade");
+  GtkBuilder *xml = builder_new ("psppire.ui");
 
   PsppireVarStore *vs = NULL;
 
@@ -156,7 +155,7 @@ transpose_dialog (GObject *o, gpointer data)
      FLIP /VARIABLES=var_list /NEWNAMES=var_name.
   */
 static gchar *
-generate_syntax (PsppireDict *dict, GladeXML *xml)
+generate_syntax (PsppireDict *dict, GtkBuilder *xml)
 {
   const gchar *text;
   GString *string = g_string_new ("FLIP");
index 43a3832c01822dd5829cc42aa317f29700e949a1..2f5495f137dd5a41f0e889cc847a210f7bf4b3e7 100644 (file)
@@ -16,7 +16,6 @@
 
 #include <config.h>
 #include <gtk/gtk.h>
-#include <glade/glade.h>
 
 #include "dict-display.h"
 #include "var-display.h"
@@ -168,7 +167,7 @@ variable_info_dialog (GObject *o, gpointer data)
 
   gint response ;
 
-  GladeXML *xml = XML_NEW ("psppire.glade");
+  GtkBuilder *xml = builder_new ("psppire.ui");
 
   GtkWidget *dialog = get_widget_assert (xml, "variable-info-dialog");
   GtkWidget *treeview = get_widget_assert (xml, "treeview2");
index 25a0aded6a5fd5ee0bb90a6cec2a451fb9314e0b..e775506f3ec30d0eeb2747865dc4425708fda1e2 100644 (file)
@@ -17,9 +17,7 @@
 #ifndef __VARIABLE_DIALOG_H
 #define __VARIABLE_DIALOG_H
 
-
 #include <gtk/gtk.h>
-#include <glade/glade.h>
 
 void variable_info_dialog (GObject *o, gpointer data);
 
index 9d103e1c97c8e6b58023afd88be4fbdf00e1ff43..a464646fe7742eeacf0c0ece78467710c0ad5de8 100644 (file)
@@ -26,7 +26,6 @@
 #include "helper.h"
 
 #include <gtk/gtk.h>
-#include <glade/glade.h>
 
 #include <gettext.h>
 #define _(msgid) gettext (msgid)
@@ -107,7 +106,7 @@ weight_cases_dialog (GObject *o, gpointer data)
   PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
   struct weight_cases_dialog wcd;
 
-  GladeXML *xml = XML_NEW ("psppire.glade");
+  GtkBuilder *xml = builder_new ("psppire.ui");
 
   GtkWidget *dialog = get_widget_assert (xml, "weight-cases-dialog");
   GtkWidget *source = get_widget_assert (xml, "weight-cases-treeview");
index 598cdddd8eefaeea38196d188be9e33baeda36f0..cd47b62e7863af1859a725b206225526fa4363e8 100644 (file)
@@ -27,10 +27,11 @@ src_ui_terminal_pspp_LDADD = \
        src/libpspp-core.la \
        $(NCURSES_LIBS) \
        $(LIBICONV) \
-       @LIBINTL@ @LIBREADLINE@
+       @LIBINTL@ @LIBREADLINE@ \
+       $(LIB_CLOSE)
 
 
-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)`
index 904c9a1dbc772bb1bcbf33d591124da8a41db9b6..e37cace39ec05af2527c6e23493689b46e75d75b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 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
@@ -89,7 +89,6 @@ main (int argc, char **argv)
   signal (SIGABRT, bug_handler);
   signal (SIGSEGV, bug_handler);
   signal (SIGFPE, bug_handler);
-  signal (SIGALRM, SIG_IGN);
   at_fatal_signal (clean_up);
 
   i18n_init ();
index 00f3a126e439a950b51a3131a726ec39945fc201..61c66bd56d65098792f3a0e91dda51736f99ecfa 100644 (file)
@@ -35,6 +35,7 @@ dist_TESTS = \
        tests/command/input-program.sh \
        tests/command/insert.sh \
        tests/command/lag.sh \
+       tests/command/line-ends.sh \
        tests/command/list.sh \
        tests/command/loop.sh \
        tests/command/longvars.sh \
@@ -213,7 +214,7 @@ tests_libpspp_heap_test_SOURCES = \
        src/libpspp/pool.c \
        src/libpspp/pool.h \
        tests/libpspp/heap-test.c
-tests_libpspp_heap_test_LDADD = gl/libgl.la @LIBINTL@
+tests_libpspp_heap_test_LDADD = gl/libgl.la @LIBINTL@ @LIB_CLOSE@
 tests_libpspp_heap_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
 
 tests_libpspp_hmap_test_SOURCES = \
@@ -263,12 +264,12 @@ tests_libpspp_range_set_test_SOURCES = \
        src/libpspp/range-set.c \
        src/libpspp/range-set.h \
        tests/libpspp/range-set-test.c
-tests_libpspp_range_set_test_LDADD = gl/libgl.la @LIBINTL@
+tests_libpspp_range_set_test_LDADD = gl/libgl.la @LIBINTL@ @LIB_CLOSE@
 tests_libpspp_range_set_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
 
 tests_libpspp_str_test_SOURCES = \
        tests/libpspp/str-test.c
-tests_libpspp_str_test_LDADD = src/libpspp/libpspp.la gl/libgl.la @LIBINTL@
+tests_libpspp_str_test_LDADD = src/libpspp/libpspp.la gl/libgl.la @LIBINTL@ @LIB_CLOSE@
 
 tests_libpspp_tower_test_SOURCES = \
        src/libpspp/abt.c \
@@ -278,7 +279,7 @@ tests_libpspp_tower_test_SOURCES = \
        src/libpspp/tower.c \
        src/libpspp/tower.h \
        tests/libpspp/tower-test.c
-tests_libpspp_tower_test_LDADD = gl/libgl.la @LIBINTL@
+tests_libpspp_tower_test_LDADD = gl/libgl.la @LIBINTL@ @LIB_CLOSE@
 tests_libpspp_tower_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
 
 tests_libpspp_sparse_array_test_SOURCES = \
@@ -287,7 +288,7 @@ tests_libpspp_sparse_array_test_SOURCES = \
        src/libpspp/pool.c \
        src/libpspp/pool.h \
        tests/libpspp/sparse-array-test.c
-tests_libpspp_sparse_array_test_LDADD = gl/libgl.la @LIBINTL@
+tests_libpspp_sparse_array_test_LDADD = gl/libgl.la @LIBINTL@ @LIB_CLOSE@
 tests_libpspp_sparse_array_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
 
 tests_formats_inexactify_SOURCES = tests/formats/inexactify.c
@@ -297,7 +298,7 @@ tests_dissect_sysfile_SOURCES = \
        src/libpspp/integer-format.c \
        src/libpspp/float-format.c \
        tests/dissect-sysfile.c
-tests_dissect_sysfile_LDADD = gl/libgl.la @LIBINTL@
+tests_dissect_sysfile_LDADD = gl/libgl.la @LIBINTL@ @LIB_CLOSE@
 tests_dissect_sysfile_CPPFLAGS = $(AM_CPPFLAGS) -DINSTALLDIR=\"$(bindir)\"
 
 EXTRA_DIST += \
index 97b192625f60b6d4752c7a1109f89fcb22705213..2cd6c14a6a00d930722149a77d5fc5da0d86fe7e 100755 (executable)
@@ -59,7 +59,7 @@ mkdir -p $TEMPDIR
 
 cd $TEMPDIR
 
-activity="create program"
+activity="create program 1"
 cat > $TESTFILE << EOF
 DATA LIST LIST /x * y *.
 BEGIN DATA.
@@ -77,7 +77,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
-activity="run program"
+activity="run program 1"
 $SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
@@ -115,4 +115,31 @@ diff -b  $TEMPDIR/pspp.list - <<EOF
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
+
+#Make sure this doesn't interfere with percentiles operation.
+
+activity="create program 2"
+cat > $TESTFILE << EOF
+DATA LIST LIST /X *.
+BEGIN DATA.
+99
+99
+5.00
+END DATA.
+
+MISSING VALUE X (99).
+
+EXAMINE /x
+        /PERCENTILES=HAVERAGE.
+
+
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+
+activity="run program 2"
+$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+if [ $? -ne 0 ] ; then fail ; fi
+
+
 pass;
index be7f9e08c565c52677a4e0704f92acd86b84a948..f80dc5fc4a0df3f1c4250ef32e0bf3bb45e7a524 100755 (executable)
@@ -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 <<EOF > $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;
diff --git a/tests/command/line-ends.sh b/tests/command/line-ends.sh
new file mode 100755 (executable)
index 0000000..ca03b5c
--- /dev/null
@@ -0,0 +1,104 @@
+#!/bin/sh
+
+# This program tests that DATA LIST can be used to read input files
+# with varying line ends (LF only, CR LF, CR only).
+
+TEMPDIR=/tmp/pspp-tst-$$
+TESTFILE=$TEMPDIR/`basename $0`.sps
+
+# ensure that top_builddir  are absolute
+if [ -z "$top_builddir" ] ; then top_builddir=. ; fi
+if [ -z "$top_srcdir" ] ; then top_srcdir=. ; fi
+top_builddir=`cd $top_builddir; pwd`
+PSPP=$top_builddir/src/ui/terminal/pspp
+
+# ensure that top_srcdir is absolute
+top_srcdir=`cd $top_srcdir; pwd`
+
+STAT_CONFIG_PATH=$top_srcdir/config
+export STAT_CONFIG_PATH
+
+
+cleanup()
+{
+     if [ x"$PSPP_TEST_NO_CLEANUP" != x ] ; then
+       echo "NOT cleaning $TEMPDIR"
+       return ;
+     fi
+     cd /
+     rm -rf $TEMPDIR
+}
+
+
+fail()
+{
+    echo $activity
+    echo FAILED
+    cleanup;
+    exit 1;
+}
+
+
+no_result()
+{
+    echo $activity
+    echo NO RESULT;
+    cleanup;
+    exit 2;
+}
+
+pass()
+{
+    cleanup;
+    exit 0;
+}
+
+mkdir -p $TEMPDIR
+
+cd $TEMPDIR
+
+# Create command file.
+activity="create program"
+cat > $TESTFILE << EOF
+data list list notable file='input.txt'/a b c.
+list.
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+
+activity="create input.txt"
+printf '1 2 3\n4 5 6\r\n7 8 9\r10 11 12\n13 14 15 \r\n16 17 18\r' > input.txt
+if [ $? -ne 0 ] ; then no_result ; fi
+
+
+# Make sure that input.txt actually received the data that we expect.
+# It might not have, if we're running on a system that translates \n
+# into some other sequence.
+activity="check input.txt"
+cksum input.txt > input.cksum
+diff input.cksum - <<EOF
+4116052799 48 input.txt
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+
+activity="run program"
+$SUPERVISOR $PSPP --testing-mode $TESTFILE
+if [ $? -ne 0 ] ; then fail ; fi
+
+
+activity="compare output"
+perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
+diff -b  $TEMPDIR/pspp.list - << EOF
+       a        b        c
+-------- -------- --------
+    1.00     2.00     3.00
+    4.00     5.00     6.00
+    7.00     8.00     9.00
+   10.00    11.00    12.00
+   13.00    14.00    15.00
+   16.00    17.00    18.00
+EOF
+if [ $? -ne 0 ] ; then fail ; fi
+
+pass;