f8479c6da06a641fc5ce8c92a271aa87f25565e2
[pspp-builds.git] / perl-module / PSPP.xs
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17    02110-1301, USA. */
18
19
20 #include <config.h>
21
22 /* The Gnulib "strftime" module defines my_strftime in <config.h> for use by
23    gl/strftime.c.  Perl also defines my_strftime in embed.h for some other
24    purpose.  The former definition doesn't matter in this file, so suppress it
25    to avoid a compiler warning. */
26 #undef my_strftime
27
28 #include "EXTERN.h"
29 #include "perl.h"
30 #include "XSUB.h"
31
32 #include "ppport.h"
33
34 #include "minmax.h"
35 #include <libpspp/message.h>
36 #include <libpspp/version.h>
37 #include <libpspp/i18n.h>
38 #include <gl/xalloc.h>
39 #include <data/dictionary.h>
40 #include <data/case.h>
41 #include <data/casereader.h>
42 #include <data/casewriter.h>
43 #include <data/variable.h>
44 #include <data/attributes.h>
45 #include <data/file-handle-def.h>
46 #include <data/identifier.h>
47 #include <data/sys-file-writer.h>
48 #include <data/sys-file-reader.h>
49 #include <data/value.h>
50 #include <data/vardict.h>
51 #include <data/value-labels.h>
52 #include <data/format.h>
53 #include <data/data-in.h>
54 #include <data/data-out.h>
55 #include <string.h>
56
57 typedef struct fmt_spec input_format ;
58 typedef struct fmt_spec output_format ;
59
60
61 /*  A thin wrapper around sfm_writer */
62 struct sysfile_info
63 {
64   bool opened;
65
66   /* A pointer to the writer. The writer is owned by the struct */
67   struct casewriter *writer;
68
69   /* A pointer to the dictionary. Owned externally */
70   const struct dictionary *dict;
71
72   /* The scalar containing the dictionary */
73   SV *dict_sv;
74 };
75
76
77 /*  A thin wrapper around sfm_reader */
78 struct sysreader_info
79 {
80   struct sfm_read_info opts;
81
82   /* A pointer to the reader. The reader is owned by the struct */
83   struct casereader *reader;
84
85   /* A pointer to the dictionary. */
86   struct dictionary *dict;
87 };
88
89
90
91 /*  A message handler which writes messages to PSPP::errstr */
92 static void
93 message_handler (const struct msg *m, void *aux)
94 {
95  SV *errstr = get_sv("PSPP::errstr", TRUE);
96  sv_setpv (errstr, m->text);
97 }
98
99 static int
100 sysfile_close (struct sysfile_info *sfi)
101 {
102   int retval ;
103   if ( ! sfi->opened )
104     return 0;
105
106   retval = casewriter_destroy (sfi->writer);
107   if (retval > 0 )
108     sfi->opened = false;
109
110   return retval;
111 }
112
113 static void
114 scalar_to_value (union value *val, SV *scalar, const struct variable *var)
115 {
116   if ( var_is_numeric (var))
117     {
118         if ( SvNOK (scalar) || SvIOK (scalar) )
119            val->f = SvNV (scalar);
120         else
121            val->f = SYSMIS;
122     }
123   else
124     {
125         STRLEN len;
126         const char *p = SvPV (scalar, len);
127         int width = var_get_width (var);
128         value_set_missing (val, width);
129         memcpy (value_str_rw (val, width), p, len);
130     }
131 }
132
133
134 static SV *
135 value_to_scalar (const union value *val, const struct variable *var)
136 {
137   if ( var_is_numeric (var))
138     {
139       if ( var_is_value_missing (var, val, MV_SYSTEM))
140         return newSVpvn ("", 0);
141
142       return newSVnv (val->f);
143     }
144   else
145     {
146       int width = var_get_width (var);
147       return newSVpvn (value_str (val, width), width);
148     }
149 }
150
151
152 static void
153 var_set_input_format (struct variable *v, input_format ip_fmt)
154 {
155   struct fmt_spec *if_copy = malloc (sizeof (*if_copy));
156   memcpy (if_copy, &ip_fmt, sizeof (ip_fmt));
157   var_attach_aux (v, if_copy, var_dtor_free);
158 }
159
160 static void
161 make_value_from_scalar (union value *uv, SV *val, const struct variable *var)
162 {
163  value_init (uv, var_get_width (var));
164  scalar_to_value (uv, val, var);
165 }
166
167
168 MODULE = PSPP
169
170 MODULE = PSPP           PACKAGE = PSPP
171
172 PROTOTYPES: ENABLE
173
174 void
175 onBoot (ver)
176  const char *ver
177 CODE:
178  /* Check that the version is correct up to the length of 'ver'.
179     This allows PSPP autobuilders to add a "-build#" suffix to the
180     PSPP version without causing failures here. */
181  assert (0 == strncmp (ver, bare_version, strlen (ver)));
182
183  i18n_init ();
184  msg_set_handler (message_handler, NULL);
185  settings_init (0, 0);
186  fh_init ();
187
188 SV *
189 format_value (val, var)
190  SV *val
191  struct variable *var
192 CODE:
193  SV *ret;
194  const struct fmt_spec *fmt = var_get_print_format (var);
195  union value uv;
196  char *s;
197  make_value_from_scalar (&uv, val, var);
198  s = data_out (&uv, var_get_encoding (var), fmt);
199  value_destroy (&uv, var_get_width (var));
200  ret = newSVpv (s, fmt->w);
201  free (s);
202  RETVAL = ret;
203  OUTPUT:
204 RETVAL
205
206
207 int
208 value_is_missing (val, var)
209  SV *val
210  struct variable *var
211 CODE:
212  union value uv;
213  int ret;
214  make_value_from_scalar (&uv, val, var);
215  ret = var_is_value_missing (var, &uv, MV_ANY);
216  value_destroy (&uv, var_get_width (var));
217  RETVAL = ret;
218  OUTPUT:
219 RETVAL
220
221
222
223 MODULE = PSPP           PACKAGE = PSPP::Dict
224
225 struct dictionary *
226 pxs_dict_new()
227 CODE:
228  RETVAL = dict_create ("UTF-8");
229 OUTPUT:
230  RETVAL
231
232
233 void
234 DESTROY (dict)
235  struct dictionary *dict
236 CODE:
237  dict_destroy (dict);
238
239
240 int
241 get_var_cnt (dict)
242  struct dictionary *dict
243 CODE:
244  RETVAL = dict_get_var_cnt (dict);
245 OUTPUT:
246 RETVAL
247
248 void
249 set_label (dict, label)
250  struct dictionary *dict
251  char *label
252 CODE:
253  dict_set_label (dict, label);
254
255 void
256 set_documents (dict, docs)
257  struct dictionary *dict
258  char *docs
259 CODE:
260  dict_set_documents_string (dict, docs);
261
262
263 void
264 add_document (dict, doc)
265  struct dictionary *dict
266  char *doc
267 CODE:
268  dict_add_document_line (dict, doc, false);
269
270
271 void
272 clear_documents (dict)
273  struct dictionary *dict
274 CODE:
275  dict_clear_documents (dict);
276
277
278 void
279 set_weight (dict, var)
280  struct dictionary *dict
281  struct variable *var
282 CODE:
283  dict_set_weight (dict, var);
284
285
286 struct variable *
287 pxs_get_variable (dict, idx)
288  struct dictionary *dict
289  SV *idx
290 INIT:
291  SV *errstr = get_sv("PSPP::errstr", TRUE);
292  sv_setpv (errstr, "");
293  if ( SvIV (idx) >= dict_get_var_cnt (dict))
294   {
295     sv_setpv (errstr, "The dictionary doesn't have that many variables.");
296     XSRETURN_UNDEF;
297   }
298 CODE:
299  RETVAL = dict_get_var (dict, SvIV (idx));
300  OUTPUT:
301 RETVAL
302
303
304 struct variable *
305 pxs_get_var_by_name (dict, name)
306  struct dictionary *dict
307  const char *name
308 INIT:
309  SV *errstr = get_sv("PSPP::errstr", TRUE);
310  sv_setpv (errstr, "");
311 CODE:
312  struct variable *var = dict_lookup_var (dict, name);
313  if ( ! var )
314       sv_setpv (errstr, "No such variable.");
315  RETVAL = var;
316  OUTPUT:
317 RETVAL
318
319
320 MODULE = PSPP           PACKAGE = PSPP::Var
321
322
323 struct variable *
324 pxs_dict_create_var (dict, name, ip_fmt)
325  struct dictionary * dict
326  char *name
327  input_format ip_fmt
328 INIT:
329  SV *errstr = get_sv("PSPP::errstr", TRUE);
330  sv_setpv (errstr, "");
331  if ( ! id_is_plausible (name, false))
332   {
333     sv_setpv (errstr, "The variable name is not valid.");
334     XSRETURN_UNDEF;
335   }
336 CODE:
337  struct fmt_spec op_fmt;
338
339  struct variable *v;
340  op_fmt = fmt_for_output_from_input (&ip_fmt);
341  v = dict_create_var (dict, name,
342         fmt_is_string (op_fmt.type) ? op_fmt.w : 0);
343  if ( NULL == v )
344   {
345     sv_setpv (errstr, "The variable could not be created (probably already exists).");
346     XSRETURN_UNDEF;
347   }
348  var_set_both_formats (v, &op_fmt);
349  var_set_input_format (v, ip_fmt);
350  RETVAL = v;
351 OUTPUT:
352  RETVAL
353
354
355 int
356 set_missing_values (var, v1, ...)
357  struct variable *var;
358  SV *v1;
359 INIT:
360  int i;
361  union value val[3];
362
363  if ( items > 4 )
364   croak ("No more than 3 missing values are permitted");
365
366  for (i = 0; i < items - 1; ++i)
367    scalar_to_value (&val[i], ST(i+1), var);
368 CODE:
369  struct missing_values mv;
370  mv_init (&mv, var_get_width (var));
371  for (i = 0 ; i < items - 1; ++i )
372    mv_add_value (&mv, &val[i]);
373  var_set_missing_values (var, &mv);
374
375
376 void
377 set_label (var, label)
378  struct variable *var;
379  char *label
380 CODE:
381   var_set_label (var, label, false);
382
383
384 void
385 clear_value_labels (var)
386  struct variable *var;
387 CODE:
388  var_clear_value_labels (var);
389
390 SV *
391 get_write_format (var)
392  struct variable *var
393 CODE:
394  HV *fmthash = (HV *) sv_2mortal ((SV *) newHV());
395  const struct fmt_spec *fmt = var_get_write_format (var);
396
397  hv_store (fmthash, "fmt", 3, newSVnv (fmt->type), 0);
398  hv_store (fmthash, "decimals", 8, newSVnv (fmt->d), 0);
399  hv_store (fmthash, "width", 5, newSVnv (fmt->w), 0);
400
401  RETVAL = newRV ((SV *) fmthash);
402  OUTPUT:
403 RETVAL
404
405 SV *
406 get_print_format (var)
407  struct variable *var
408 CODE:
409  HV *fmthash = (HV *) sv_2mortal ((SV *) newHV());
410  const struct fmt_spec *fmt = var_get_print_format (var);
411
412  hv_store (fmthash, "fmt", 3, newSVnv (fmt->type), 0);
413  hv_store (fmthash, "decimals", 8, newSVnv (fmt->d), 0);
414  hv_store (fmthash, "width", 5, newSVnv (fmt->w), 0);
415
416  RETVAL = newRV ((SV *) fmthash);
417  OUTPUT:
418 RETVAL
419
420
421 void
422 pxs_set_write_format (var, fmt)
423  struct variable *var
424  output_format fmt
425 CODE:
426  var_set_write_format (var, &fmt);
427
428
429 void
430 pxs_set_print_format (var, fmt)
431  struct variable *var
432  output_format fmt
433 CODE:
434  var_set_print_format (var, &fmt);
435
436 void
437 pxs_set_output_format (var, fmt)
438  struct variable *var
439  output_format fmt
440 CODE:
441  var_set_both_formats (var, &fmt);
442
443
444 int
445 add_value_label (var, key, label)
446  struct variable *var
447  SV *key
448  char *label
449 INIT:
450  SV *errstr = get_sv("PSPP::errstr", TRUE);
451  sv_setpv (errstr, "");
452 CODE:
453  union value the_value;
454  int width = var_get_width (var);
455  int ok;
456
457  value_init (&the_value, width);
458  if ( var_is_numeric (var))
459  {
460   if ( ! looks_like_number (key))
461     {
462       sv_setpv (errstr, "Cannot add label with string key to a numeric variable");
463       value_destroy (&the_value, width);
464       XSRETURN_IV (0);
465     }
466   the_value.f = SvNV (key);
467  }
468  else
469  {
470   value_copy_str_rpad (&the_value, width, SvPV_nolen(key), ' ');
471  }
472  ok = var_add_value_label (var, &the_value, label);
473  value_destroy (&the_value, width);
474  if (!ok)
475  {
476    sv_setpv (errstr, "Something went wrong");
477    XSRETURN_IV (0);
478  }
479  XSRETURN_IV (1);
480
481
482 SV *
483 get_attributes (var)
484  struct variable *var
485 CODE:
486  HV *attrhash = (HV *) sv_2mortal ((SV *) newHV());
487
488  struct attrset *as = var_get_attributes (var);
489
490  if ( as )
491    {
492      struct attrset_iterator iter;
493      struct attribute *attr;
494
495      for (attr = attrset_first (as, &iter);
496           attr;
497           attr = attrset_next (as, &iter))
498        {
499          int i;
500          const char *name = attribute_get_name (attr);
501
502          AV *values = newAV ();
503
504          for (i = 0 ; i < attribute_get_n_values (attr); ++i )
505            {
506              const char *value = attribute_get_value (attr, i);
507              av_push (values, newSVpv (value, 0));
508            }
509
510          hv_store (attrhash, name, strlen (name),
511                    newRV_noinc ((SV*) values), 0);
512        }
513    }
514
515  RETVAL = newRV ((SV *) attrhash);
516  OUTPUT:
517 RETVAL
518
519
520 const char *
521 get_name (var)
522  struct variable * var
523 CODE:
524  RETVAL = var_get_name (var);
525  OUTPUT:
526 RETVAL
527
528
529 const char *
530 get_label (var)
531  struct variable * var
532 CODE:
533  RETVAL = var_get_label (var);
534  OUTPUT:
535 RETVAL
536
537
538 SV *
539 get_value_labels (var)
540  struct variable *var
541 CODE:
542  HV *labelhash = (HV *) sv_2mortal ((SV *) newHV());
543  const struct val_lab *vl;
544  struct val_labs_iterator *viter = NULL;
545  const struct val_labs *labels = var_get_value_labels (var);
546
547  if ( labels )
548    {
549      for (vl = val_labs_first (labels);
550           vl;
551           vl = val_labs_next (labels, vl))
552        {
553          SV *sv = value_to_scalar (&vl->value, var);
554          STRLEN len;
555          const char *s = SvPV (sv, len);
556          hv_store (labelhash, s, len, newSVpv (val_lab_get_label (vl), 0), 0);
557        }
558    }
559
560  RETVAL = newRV ((SV *) labelhash);
561  OUTPUT:
562 RETVAL
563
564
565
566 MODULE = PSPP           PACKAGE = PSPP::Sysfile
567
568
569 struct sysfile_info *
570 pxs_create_sysfile (name, dict_ref, opts_hr)
571  char *name
572  SV *dict_ref
573  SV *opts_hr
574 INIT:
575  SV *dict_sv = SvRV (dict_ref);
576  struct dictionary *dict = (void *) SvIV (dict_sv);
577  struct sfm_write_options opts;
578  if (!SvROK (opts_hr))
579   {
580     opts = sfm_writer_default_options ();
581   }
582  else
583   {
584     HV *opt_h = (HV *) SvRV (opts_hr);
585     SV** readonly = hv_fetch(opt_h, "readonly", 8, 0);
586     SV** compress = hv_fetch(opt_h, "compress", 8, 0);
587     SV** version = hv_fetch(opt_h, "version", 7, 0);
588
589     opts.create_writeable = readonly ? ! SvIV (*readonly) : true;
590     opts.compress = compress ? SvIV (*compress) : false;
591     opts.version = version ? SvIV (*version) : 3 ;
592   }
593 CODE:
594  struct file_handle *fh =
595   fh_create_file (NULL, name, fh_default_properties () );
596  struct sysfile_info *sfi = xmalloc (sizeof (*sfi));
597  sfi->writer = sfm_open_writer (fh, dict, opts);
598  sfi->dict = dict;
599  sfi->opened = true;
600  sfi->dict_sv = dict_sv;
601  SvREFCNT_inc (sfi->dict_sv);
602  
603  RETVAL = sfi;
604  OUTPUT:
605 RETVAL
606
607 int
608 close (sfi)
609  struct sysfile_info *sfi
610 CODE:
611  RETVAL = sysfile_close (sfi);
612 OUTPUT:
613  RETVAL
614
615 void
616 DESTROY (sfi)
617  struct sysfile_info *sfi
618 CODE:
619  sysfile_close (sfi);
620  SvREFCNT_dec (sfi->dict_sv);
621  free (sfi);
622
623 int
624 append_case (sfi, ccase)
625  struct sysfile_info *sfi
626  SV *ccase
627 INIT:
628  SV *errstr = get_sv("PSPP::errstr", TRUE);
629  sv_setpv (errstr, "");
630  if ( (!SvROK(ccase)))
631   {
632     XSRETURN_UNDEF;
633   }
634 CODE:
635  int i = 0;
636  AV *av_case = (AV*) SvRV (ccase);
637
638  const struct variable **vv;
639  size_t nv;
640  struct ccase *c;
641  SV *sv;
642
643  if ( av_len (av_case) >= dict_get_var_cnt (sfi->dict))
644    XSRETURN_UNDEF;
645
646  c =  case_create (dict_get_proto (sfi->dict));
647
648  dict_get_vars (sfi->dict, &vv, &nv, 1u << DC_ORDINARY | 1u << DC_SYSTEM);
649
650  for (sv = av_shift (av_case); SvOK (sv);  sv = av_shift (av_case))
651  {
652     const struct variable *v = vv[i++];
653     const struct fmt_spec *ifmt = var_get_aux (v);
654
655     /* If an input format has been set, then use it.
656        Otherwise just convert the raw value.
657     */
658     if ( ifmt )
659       {
660         struct substring ss = ss_cstr (SvPV_nolen (sv));
661         char *error;
662         bool ok;
663
664         error = data_in (ss, SvUTF8(sv) ? UTF8: "iso-8859-1", ifmt->type,
665                          case_data_rw (c, v), var_get_width (v),
666                          dict_get_encoding (sfi->dict));
667         ok = error == NULL;
668         free (error);
669
670         if ( !ok )
671           {
672             RETVAL = 0;
673             goto finish;
674           }
675       }
676     else
677       {
678         scalar_to_value (case_data_rw (c, v), sv, v);
679       }
680  }
681
682  /* The remaining variables must be sysmis or blank string */
683  while (i < dict_get_var_cnt (sfi->dict))
684  {
685    const struct variable *v = vv[i++];
686    union value *val = case_data_rw (c, v);
687    value_set_missing (val, var_get_width (v));
688  }
689  casewriter_write (sfi->writer, c);
690  RETVAL = 1;
691  finish:
692  free (vv);
693 OUTPUT:
694  RETVAL
695
696
697 \f
698
699 MODULE = PSPP           PACKAGE = PSPP::Reader
700
701 struct sysreader_info *
702 pxs_open_sysfile (name)
703  char * name
704 CODE:
705  struct casereader *reader;
706  struct sysreader_info *sri = NULL;
707  struct file_handle *fh =
708          fh_create_file (NULL, name, fh_default_properties () );
709
710  sri = xmalloc (sizeof (*sri));
711  sri->reader = sfm_open_reader (fh, &sri->dict, &sri->opts);
712
713  if ( NULL == sri->reader)
714  {
715    free (sri);
716    sri = NULL;
717  }
718
719  RETVAL = sri;
720  OUTPUT:
721 RETVAL
722
723
724 struct dictionary *
725 pxs_get_dict (reader)
726  struct sysreader_info *reader;
727 CODE:
728  RETVAL = reader->dict;
729  OUTPUT:
730 RETVAL
731
732 SV *
733 get_case_cnt (sfr)
734  struct sysreader_info *sfr;
735 CODE:
736  SV *ret;
737  casenumber n = casereader_get_case_cnt (sfr->reader);
738  if (n == CASENUMBER_MAX)
739   ret = &PL_sv_undef;
740  else 
741   ret = newSViv (n);
742  RETVAL = ret;
743  OUTPUT:
744 RETVAL
745
746
747
748 void
749 get_next_case (sfr)
750  struct sysreader_info *sfr;
751 PPCODE:
752  struct ccase *c;
753
754  if ((c = casereader_read (sfr->reader)) != NULL)
755  {
756   int v;
757
758   EXTEND (SP, dict_get_var_cnt (sfr->dict));
759   for (v = 0; v < dict_get_var_cnt (sfr->dict); ++v )
760     {
761       const struct variable *var = dict_get_var (sfr->dict, v);
762       const union value *val = case_data (c, var);
763
764       PUSHs (sv_2mortal (value_to_scalar (val, var)));
765     }
766
767   case_unref (c);
768  }