Added functions to enable reading data files from perl
[pspp-builds.git] / perl-module / PSPP.xs
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2007, 2008 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 "EXTERN.h"
21 #include "perl.h"
22 #include "XSUB.h"
23
24 #include <config.h>
25
26 #include "ppport.h"
27
28 #include "minmax.h"
29 #include <libpspp/message.h>
30 #include <libpspp/version.h>
31 #include <gl/xalloc.h>
32 #include <data/dictionary.h>
33 #include <data/case.h>
34 #include <data/variable.h>
35 #include <data/file-handle-def.h>
36 #include <data/sys-file-writer.h>
37 #include <data/sys-file-reader.h>
38 #include <data/value.h>
39 #include <data/value-labels.h>
40 #include <data/format.h>
41 #include <data/data-in.h>
42 #include <string.h>
43
44 typedef struct fmt_spec input_format ;
45 typedef struct fmt_spec output_format ;
46
47
48 /*  A thin wrapper around sfm_writer */
49 struct sysfile_info
50 {
51   bool opened;
52
53   /* A pointer to the writer. The writer is owned by the struct */
54   struct casewriter *writer;
55
56   /* A pointer to the dictionary. Owned externally */
57   const struct dictionary *dict;
58 };
59
60
61 /*  A thin wrapper around sfm_reader */
62 struct sysreader_info
63 {
64   struct sfm_read_info opts;
65
66   /* A pointer to the reader. The reader is owned by the struct */
67   struct casereader *reader;
68
69   /* A pointer to the dictionary. */
70   struct dictionary *dict;
71 };
72
73
74
75 /*  A message handler which writes messages to PSPP::errstr */
76 static void
77 message_handler (const struct msg *m)
78 {
79  SV *errstr = get_sv("PSPP::errstr", TRUE);
80  sv_setpv (errstr, m->text);
81 }
82
83 static int
84 sysfile_close (struct sysfile_info *sfi)
85 {
86   int retval ;
87   if ( ! sfi->opened )
88     return 0;
89
90   retval = casewriter_destroy (sfi->writer);
91   if (retval > 0 )
92     sfi->opened = false;
93
94   return retval;
95 }
96
97 static void
98 scalar_to_value (union value *val, SV *scalar, const struct variable *var)
99 {
100   if ( var_is_numeric (var))
101     {
102         if ( SvNOK (scalar) || SvIOK (scalar) )
103            val->f = SvNV (scalar);
104         else
105            val->f = SYSMIS;
106     }
107   else
108     {
109         STRLEN len;
110         const char *p = SvPV (scalar, len);
111         memset (val->s, ' ', var_get_width (var));
112         memcpy (val->s, p, len);
113     }
114 }
115
116
117 static SV *
118 value_to_scalar (const union value *val, const struct variable *var)
119 {
120   if ( var_is_numeric (var))
121     {
122       if ( var_is_value_missing (var, val, MV_SYSTEM))
123         return newSVpvn ("", 0);
124
125       return newSVnv (val->f);
126     }
127   else
128     return newSVpvn (val->s, var_get_width (var));
129 }
130
131
132 static void
133 var_set_input_format (struct variable *v, input_format ip_fmt)
134 {
135   struct fmt_spec *if_copy = malloc (sizeof (*if_copy));
136   memcpy (if_copy, &ip_fmt, sizeof (ip_fmt));
137   var_attach_aux (v, if_copy, var_dtor_free);
138 }
139
140 static union value *
141 make_value_from_scalar (SV *val, const struct variable *var)
142 {
143  union value *uv = value_create (var_get_width (var));
144  scalar_to_value (uv, val, var);
145  return uv;
146 }
147
148
149 MODULE = PSPP
150
151 BOOT:
152  msg_init (NULL, message_handler);
153  settings_init (0, 0);
154  fh_init ();
155
156
157 MODULE = PSPP           PACKAGE = PSPP
158
159 SV *
160 format_value (val, var)
161  SV *val
162  struct variable *var
163 CODE:
164  SV *ret;
165  const struct fmt_spec *fmt = var_get_print_format (var);
166  union value *uv = make_value_from_scalar (val, var);
167  char *s;
168  s = malloc (fmt->w);
169  memset (s, '\0', fmt->w);
170  data_out (uv, fmt, s);
171  free (uv);
172  ret = newSVpv (s, fmt->w);
173  free (s);
174  RETVAL = ret;
175  OUTPUT:
176 RETVAL
177  
178
179 int
180 value_is_missing (val, var)
181  SV *val
182  struct variable *var
183 CODE:
184  union value *uv = make_value_from_scalar (val, var);
185  int ret = var_is_value_missing (var, uv, MV_ANY);
186  free (uv);
187  RETVAL = ret;
188  OUTPUT:
189 RETVAL
190
191
192
193 MODULE = PSPP           PACKAGE = PSPP::Dict
194
195 struct dictionary *
196 pxs_dict_new()
197 CODE:
198  RETVAL = dict_create ();
199 OUTPUT:
200  RETVAL
201
202
203 void
204 DESTROY (dict)
205  struct dictionary *dict
206 CODE:
207  dict_destroy (dict);
208
209
210 int
211 get_var_cnt (dict)
212  struct dictionary *dict
213 CODE:
214  RETVAL = dict_get_var_cnt (dict);
215 OUTPUT:
216 RETVAL
217
218 void
219 set_label (dict, label)
220  struct dictionary *dict
221  char *label
222 CODE:
223  dict_set_label (dict, label);
224
225 void
226 set_documents (dict, docs)
227  struct dictionary *dict
228  char *docs
229 CODE:
230  dict_set_documents (dict, docs);
231
232
233 void
234 add_document (dict, doc)
235  struct dictionary *dict
236  char *doc
237 CODE:
238  dict_add_document_line (dict, doc);
239
240
241 void
242 clear_documents (dict)
243  struct dictionary *dict
244 CODE:
245  dict_clear_documents (dict);
246
247
248 void
249 set_weight (dict, var)
250  struct dictionary *dict
251  struct variable *var
252 CODE:
253  dict_set_weight (dict, var);
254
255
256 struct variable *
257 pxs_get_variable (dict, idx)
258  struct dictionary *dict
259  SV *idx
260 INIT:
261  SV *errstr = get_sv("PSPP::errstr", TRUE);
262  sv_setpv (errstr, "");
263  if ( SvIV (idx) >= dict_get_var_cnt (dict))
264   {
265     sv_setpv (errstr, "The dictionary doesn't have that many variables.");
266     XSRETURN_UNDEF;
267   }
268 CODE:
269  RETVAL = dict_get_var (dict, SvIV (idx));
270  OUTPUT:
271 RETVAL
272
273 MODULE = PSPP           PACKAGE = PSPP::Var
274
275
276 struct variable *
277 pxs_dict_create_var (dict, name, ip_fmt)
278  struct dictionary * dict
279  char *name
280  input_format ip_fmt
281 INIT:
282  SV *errstr = get_sv("PSPP::errstr", TRUE);
283  sv_setpv (errstr, "");
284  if ( ! var_is_plausible_name (name, false))
285   {
286     sv_setpv (errstr, "The variable name is not valid.");
287     XSRETURN_UNDEF;
288   }
289 CODE:
290  struct fmt_spec op_fmt;
291
292  struct variable *v;
293  op_fmt = fmt_for_output_from_input (&ip_fmt);
294  v = dict_create_var (dict, name,
295         fmt_is_string (op_fmt.type) ? op_fmt.w : 0);
296  if ( NULL == v )
297   {
298     sv_setpv (errstr, "The variable could not be created (probably already exists).");
299     XSRETURN_UNDEF;
300   }
301  var_set_both_formats (v, &op_fmt);
302  var_set_input_format (v, ip_fmt);
303  RETVAL = v;
304 OUTPUT:
305  RETVAL
306
307
308 int
309 set_missing_values (var, v1, ...)
310  struct variable *var;
311  SV *v1;
312 INIT:
313  int i;
314  union value val[3];
315
316  if ( items > 4 )
317   croak ("No more than 3 missing values are permitted");
318
319  for (i = 0; i < items - 1; ++i)
320    scalar_to_value (&val[i], ST(i+1), var);
321 CODE:
322  struct missing_values mv;
323  mv_init (&mv, var_get_width (var));
324  for (i = 0 ; i < items - 1; ++i )
325    mv_add_value (&mv, &val[i]);
326  var_set_missing_values (var, &mv);
327
328
329 void
330 set_label (var, label)
331  struct variable *var;
332  char *label
333 CODE:
334   var_set_label (var, label);
335
336
337 void
338 clear_value_labels (var)
339  struct variable *var;
340 CODE:
341  var_clear_value_labels (var);
342
343 void
344 pxs_set_write_format (var, fmt)
345  struct variable *var
346  output_format fmt
347 CODE:
348  var_set_write_format (var, &fmt);
349
350
351 void
352 pxs_set_print_format (var, fmt)
353  struct variable *var
354  output_format fmt
355 CODE:
356  var_set_print_format (var, &fmt);
357
358 void
359 pxs_set_output_format (var, fmt)
360  struct variable *var
361  output_format fmt
362 CODE:
363  var_set_both_formats (var, &fmt);
364
365
366 int
367 add_value_label (var, key, label)
368  struct variable *var
369  SV *key
370  char *label
371 INIT:
372  SV *errstr = get_sv("PSPP::errstr", TRUE);
373  sv_setpv (errstr, "");
374 CODE:
375  union value the_value;
376
377  if ( var_is_numeric (var))
378  {
379   if ( ! looks_like_number (key))
380     {
381       sv_setpv (errstr, "Cannot add label with string key to a numeric variable");
382       XSRETURN_IV (0);
383     }
384   the_value.f = SvNV (key);
385  }
386  else
387  {
388    if ( var_is_long_string (var) )
389      {
390       sv_setpv (errstr, "Cannot add label to a long string variable");
391       XSRETURN_IV (0);
392      }
393   strncpy (the_value.s, SvPV_nolen(key), MAX_SHORT_STRING);
394  }
395  if (! var_add_value_label (var, &the_value, label) )
396  {
397    sv_setpv (errstr, "Something went wrong");
398    XSRETURN_IV (0);
399  }
400  XSRETURN_IV (1);
401
402
403
404 const char *
405 get_name (var)
406  struct variable * var
407 CODE:
408  RETVAL = var_get_name (var);
409  OUTPUT:
410 RETVAL
411
412
413 const char *
414 get_label (var)
415  struct variable * var
416 CODE:
417  RETVAL = var_get_label (var);
418  OUTPUT:
419 RETVAL
420
421
422 SV *
423 get_value_labels (var)
424  struct variable *var
425 CODE:
426  HV *labelhash = (HV *) sv_2mortal ((SV *) newHV());
427  struct val_lab *vl;
428  struct val_labs_iterator *viter = NULL;
429  const struct val_labs *labels = var_get_value_labels (var);
430
431  if ( labels )
432    {
433      for (vl = val_labs_first (labels, &viter);
434           vl;
435           vl = val_labs_next (labels, &viter))
436        {
437          SV *sv = value_to_scalar (&vl->value, var);
438          STRLEN len;
439          const char *s = SvPV (sv, len);
440          hv_store (labelhash, s, len, newSVpv (vl->label, 0), 0);
441        }
442    }
443
444  RETVAL = newRV ((SV *) labelhash);
445  OUTPUT:
446 RETVAL
447
448
449
450 MODULE = PSPP           PACKAGE = PSPP::Sysfile
451
452
453 struct sysfile_info *
454 pxs_create_sysfile (name, dict, opts_hr)
455  char *name
456  struct dictionary *dict
457  SV *opts_hr
458 INIT:
459  struct sfm_write_options opts;
460  if (!SvROK (opts_hr))
461   {
462     opts = sfm_writer_default_options ();
463   }
464  else
465   {
466     HV *opt_h = (HV *) SvRV (opts_hr);
467     SV** readonly = hv_fetch(opt_h, "readonly", 8, 0);
468     SV** compress = hv_fetch(opt_h, "compress", 8, 0);
469     SV** version = hv_fetch(opt_h, "version", 7, 0);
470
471     opts.create_writeable = readonly ? ! SvIV (*readonly) : true;
472     opts.compress = compress ? SvIV (*compress) : false;
473     opts.version = version ? SvIV (*version) : 3 ;
474   }
475 CODE:
476  struct file_handle *fh =
477   fh_create_file (NULL, name, fh_default_properties () );
478  struct sysfile_info *sfi = xmalloc (sizeof (*sfi));
479  sfi->writer = sfm_open_writer (fh, dict, opts);
480  sfi->dict = dict;
481  sfi->opened = true;
482  
483  RETVAL = sfi;
484  OUTPUT:
485 RETVAL
486
487 int
488 close (sfi)
489  struct sysfile_info *sfi
490 CODE:
491  RETVAL = sysfile_close (sfi);
492 OUTPUT:
493  RETVAL
494
495 void
496 DESTROY (sfi)
497  struct sysfile_info *sfi
498 CODE:
499  sysfile_close (sfi);
500  free (sfi);
501
502 int
503 append_case (sfi, ccase)
504  struct sysfile_info *sfi
505  SV *ccase
506 INIT:
507  SV *errstr = get_sv("PSPP::errstr", TRUE);
508  sv_setpv (errstr, "");
509  if ( (!SvROK(ccase)))
510   {
511     XSRETURN_UNDEF;
512   }
513 CODE:
514  int i = 0;
515  AV *av_case = (AV*) SvRV (ccase);
516
517  const struct variable **vv;
518  size_t nv;
519  struct ccase c;
520  SV *sv;
521
522  if ( av_len (av_case) >= dict_get_var_cnt (sfi->dict))
523    XSRETURN_UNDEF;
524
525  case_create (&c, dict_get_next_value_idx (sfi->dict));
526
527  dict_get_vars (sfi->dict, &vv, &nv, 1u << DC_ORDINARY | 1u << DC_SYSTEM);
528
529  for (sv = av_shift (av_case); SvOK (sv);  sv = av_shift (av_case))
530  {
531     const struct variable *v = vv[i++];
532     const struct fmt_spec *ifmt = var_get_aux (v);
533
534     /* If an input format has been set, then use it.
535        Otherwise just convert the raw value.
536     */
537     if ( ifmt )
538       {
539         struct substring ss = ss_cstr (SvPV_nolen (sv));
540         if ( ! data_in (ss, LEGACY_NATIVE, ifmt->type, 0, 0, 0,
541                         case_data_rw (&c, v),
542                         var_get_width (v)) )
543           {
544             RETVAL = 0;
545             goto finish;
546           }
547       }
548     else
549       {
550         scalar_to_value (case_data_rw (&c, v), sv, v);
551       }
552  }
553
554  /* The remaining variables must be sysmis or blank string */
555  while (i < dict_get_var_cnt (sfi->dict))
556  {
557    const struct variable *v = vv[i++];
558    union value *val = case_data_rw (&c, v);
559    if ( var_is_numeric (v))
560         val->f = SYSMIS;
561    else
562         memset (val->s, ' ', var_get_width (v));
563  }
564  RETVAL = casewriter_write (sfi->writer, &c);
565  finish:
566 // Case_destroy (&c);
567  free (vv);
568 OUTPUT:
569  RETVAL
570
571
572 \f
573
574 MODULE = PSPP           PACKAGE = PSPP::Reader
575
576 struct sysreader_info *
577 pxs_open_sysfile (name)
578  char * name
579 CODE:
580  struct casereader *reader;
581  struct sysreader_info *sri = NULL;
582  struct file_handle *fh =
583          fh_create_file (NULL, name, fh_default_properties () );
584
585  sri = xmalloc (sizeof (*sri));
586  sri->reader = sfm_open_reader (fh, &sri->dict, &sri->opts);
587
588  if ( NULL == sri->reader)
589  {
590    free (sri);
591    sri = NULL;
592  }
593
594  RETVAL = sri;
595  OUTPUT:
596 RETVAL
597
598
599 struct dictionary *
600 pxs_get_dict (reader)
601  struct sysreader_info *reader;
602 CODE:
603  RETVAL = reader->dict;
604  OUTPUT:
605 RETVAL
606
607
608 SV *
609 get_next_case (sfr)
610  struct sysreader_info *sfr;
611 CODE:
612  struct ccase c;
613
614  if (! casereader_read (sfr->reader, &c))
615  {
616   RETVAL = 0;
617  }
618  else
619  {
620   int v;
621   AV *av_case = (AV *) sv_2mortal ((SV *) newAV());
622
623   for (v = 0; v < dict_get_var_cnt (sfr->dict); ++v )
624     {
625       const struct variable *var = dict_get_var (sfr->dict, v);
626       const union value *val = case_data (&c, var);
627
628       av_push (av_case, value_to_scalar (val, var));
629     }
630
631   case_destroy (&c);
632   RETVAL = newRV ((SV *) av_case);
633  }
634 OUTPUT:
635  RETVAL
636
637