From 66b1b93cf6ca53c86199e88e5972f3017c56314c Mon Sep 17 00:00:00 2001 From: John Darrington Date: Sun, 21 Dec 2008 16:53:09 +0900 Subject: [PATCH] Integrated the perl module into the pspp build system. --- Makefile.am | 2 + perl-module/COPYING | 340 +++ perl-module/Changes | 9 + perl-module/Examples.pod | 105 + perl-module/MANIFEST | 13 + perl-module/Makefile.PL | 50 + perl-module/PSPP.bs | 0 perl-module/PSPP.xs | 400 +++ perl-module/README | 48 + perl-module/automake.mk | 79 + perl-module/lib/PSPP.pm | 400 +++ perl-module/ppport.h | 4954 ++++++++++++++++++++++++++++++++++++++ perl-module/t/Pspp.t | 266 ++ perl-module/typemap | 52 + 14 files changed, 6718 insertions(+) create mode 100644 perl-module/COPYING create mode 100644 perl-module/Changes create mode 100644 perl-module/Examples.pod create mode 100644 perl-module/MANIFEST create mode 100644 perl-module/Makefile.PL create mode 100644 perl-module/PSPP.bs create mode 100644 perl-module/PSPP.xs create mode 100644 perl-module/README create mode 100644 perl-module/automake.mk create mode 100644 perl-module/lib/PSPP.pm create mode 100644 perl-module/ppport.h create mode 100644 perl-module/t/Pspp.t create mode 100644 perl-module/typemap diff --git a/Makefile.am b/Makefile.am index 23305294..4fb848d2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -60,6 +60,8 @@ if WITH_GUI_TOOLS include $(top_srcdir)/glade/automake.mk endif +include $(top_srcdir)/perl-module/automake.mk + PHONY += $(DIST_HOOKS) dist-hook: $(DIST_HOOKS) .PHONY: $(PHONY) diff --git a/perl-module/COPYING b/perl-module/COPYING new file mode 100644 index 00000000..623b6258 --- /dev/null +++ b/perl-module/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE 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. + + 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 +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. diff --git a/perl-module/Changes b/perl-module/Changes new file mode 100644 index 00000000..785ada5a --- /dev/null +++ b/perl-module/Changes @@ -0,0 +1,9 @@ +Revision history for Perl extension Pspp. + +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 index 00000000..fc3f0167 --- /dev/null +++ b/perl-module/Examples.pod @@ -0,0 +1,105 @@ +=pod + +=head1 PSPP::Examples + +This page shows some simple examples of using the PSPP module. +See L for details on each of the subroutines. + +=head2 A Simple example + +This example creates a system file called F, 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(); + +=cut \ No newline at end of file diff --git a/perl-module/MANIFEST b/perl-module/MANIFEST new file mode 100644 index 00000000..25469055 --- /dev/null +++ b/perl-module/MANIFEST @@ -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 index 00000000..40b14efd --- /dev/null +++ b/perl-module/Makefile.PL @@ -0,0 +1,50 @@ +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 $src = prompt ("Enter the location of the full pspp source","../pspp"); + my $build = prompt ("Enter the location of the pspp build directory", "$src" ); + + %Locations = (SourceDir => "$src", BuildDir => "$build"); +}; + +WriteMakefile( + NAME => 'PSPP', + VERSION_FROM => "$Locations{BuildDir}/src/libpspp/version.c", + PREREQ_PM => {POSIX=>0}, + ($] >= 5.005 ? ## Add these new keywords supported since 5.005 + (ABSTRACT_FROM => 'lib/PSPP.pm', # retrieve abstract from module + AUTHOR => 'John Darrington ') : ()), + 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\$(LIB_EXT)", + 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 index 00000000..e69de29b diff --git a/perl-module/PSPP.xs b/perl-module/PSPP.xs new file mode 100644 index 00000000..7a3103e1 --- /dev/null +++ b/perl-module/PSPP.xs @@ -0,0 +1,400 @@ +/* PSPP - computes sample statistics. + Copyright (C) 2007 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 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 + +#include "ppport.h" + +#include "minmax.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; +}; + + +/* 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) +{ + if ( looks_like_number (scalar)) + { + val->f = SvNV (scalar); + } + else + { + STRLEN len; + char *p = SvPV (scalar, len); + memset (val->s, ' ', MAX_SHORT_STRING); + memcpy (val->s, p, len); + } +} + + +MODULE = PSPP + +BOOT: + msg_init (NULL, message_handler); + settings_init (0, 0); + fh_init (); + + +MODULE = PSPP PACKAGE = PSPP::Dict + +struct dictionary * +_dict_new() +CODE: + RETVAL = dict_create (); +OUTPUT: + RETVAL + + +void +DESTROY (dict) + struct dictionary *dict +CODE: + dict_destroy (dict); + + +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); + + + +MODULE = PSPP PACKAGE = PSPP::Var + +struct variable * +_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 fmt_spec *if_copy; + 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); + if_copy = malloc (sizeof (*if_copy)); + memcpy (if_copy, &ip_fmt, sizeof (ip_fmt)); + var_attach_aux (v, if_copy, var_dtor_free); + 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)); +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 +_set_write_format (var, fmt) + struct variable *var + output_format fmt +CODE: + var_set_write_format (var, &fmt); + + +void +_set_print_format (var, fmt) + struct variable *var + output_format fmt +CODE: + var_set_print_format (var, &fmt); + +void +_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); + + + +MODULE = PSPP PACKAGE = PSPP::Sysfile + + +struct sysfile_info * +_create_sysfile (name, dict, opts_hr) + char * name + struct dictionary * dict + SV *opts_hr +INIT: + 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; + 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); + 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; + + if ( av_len (av_case) >= dict_get_var_cnt (sfi->dict)) + XSRETURN_UNDEF; + + case_create (&c, dict_get_next_value_idx (sfi->dict)); + + dict_get_vars (sfi->dict, &vv, &nv, 1u << DC_ORDINARY | 1u << DC_SYSTEM); + + SV *sv ; + for (sv = av_shift (av_case); SvOK (sv); sv = av_shift (av_case)) + { + const struct variable *v = vv[i++]; + struct substring ss = ss_cstr (SvPV_nolen (sv)); + struct fmt_spec *ifmt = var_get_aux (v); + + if ( ! data_in (ss, LEGACY_NATIVE, ifmt->type, 0, 0, 0, case_data_rw (&c, v), + var_get_width (v)) ) + { + RETVAL = 0; + goto finish; + } + } + /* 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: + case_destroy (&c); + free (vv); +OUTPUT: + RETVAL diff --git a/perl-module/README b/perl-module/README new file mode 100644 index 00000000..39ec585d --- /dev/null +++ b/perl-module/README @@ -0,0 +1,48 @@ +PSPP version 0.01 +================= + +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.4.4 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 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 index 00000000..f3eb19d7 --- /dev/null +++ b/perl-module/automake.mk @@ -0,0 +1,79 @@ +## 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) + +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 ; \ + fi ; \ + done \ + fi + $(MAKE) $(AM_MAKEFLAGS) module-make + +check-local: + 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 + +#install-data-local: +# cd perl-module && $(MAKE) $(AM_MAKEFLAGS) doc_install +# +#install-exec-local: +# cd perl-module && $(MAKE) $(AM_MAKEFLAGS) pure_install +# +#uninstall-local: +# cd perl-module && $(MAKE) $(AM_MAKEFLAGS) uninstall +# + + +CLEANFILES += \ + 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 index 00000000..783ae256 --- /dev/null +++ b/perl-module/lib/PSPP.pm @@ -0,0 +1,400 @@ +use 5.008008; +use strict; +use warnings; + +our $VERSION = '0.7.0'; + +=head1 NAME + +PSPP - Perl extension to PSPP + +=head1 SYNOPSIS + + use PSPP; + +=head1 DESCRIPTION + +PSPP:: provides an interface to the libraries used by pspp to create +system files. + +=head1 EXPORT + +None by default. + +=cut + +require XSLoader; +XSLoader::load('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 + # 1st January 1970 + # and 14th October 1582 + }; + + + +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. + +=head3 add_document ($string) + +Appends C to the documents. + +=head3 clear_documents () + +Removes all documents. + +=head3 set_weight ($var) + +Sets the weighting variable to C. + +=cut + +sub new +{ + my $class = shift; + my $self = _dict_new (); + bless ($self, $class); + return $self; +} + +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 defines floating point format, and +C 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. The +new variable will have the name C. +The input format is set by the C parameter +(See L). +By default, the write and print formats are the same as the input format. +The write and print formats may be changed (See L), +L). 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 = _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