Merge branch 'master' of /home/john/Development/pspp-bare
[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 MODULE = PSPP           PACKAGE = PSPP
152
153 void
154 onBoot (ver)
155  const char *ver
156 CODE:
157  assert (0 == strcmp (ver, bare_version));
158  msg_init (NULL, message_handler);
159  settings_init (0, 0);
160  fh_init ();
161
162 SV *
163 format_value (val, var)
164  SV *val
165  struct variable *var
166 CODE:
167  SV *ret;
168  const struct fmt_spec *fmt = var_get_print_format (var);
169  union value *uv = make_value_from_scalar (val, var);
170  char *s;
171  s = malloc (fmt->w);
172  memset (s, '\0', fmt->w);
173  data_out (uv, fmt, s);
174  free (uv);
175  ret = newSVpv (s, fmt->w);
176  free (s);
177  RETVAL = ret;
178  OUTPUT:
179 RETVAL
180  
181
182 int
183 value_is_missing (val, var)
184  SV *val
185  struct variable *var
186 CODE:
187  union value *uv = make_value_from_scalar (val, var);
188  int ret = var_is_value_missing (var, uv, MV_ANY);
189  free (uv);
190  RETVAL = ret;
191  OUTPUT:
192 RETVAL
193
194
195
196 MODULE = PSPP           PACKAGE = PSPP::Dict
197
198 struct dictionary *
199 pxs_dict_new()
200 CODE:
201  RETVAL = dict_create ();
202 OUTPUT:
203  RETVAL
204
205
206 void
207 DESTROY (dict)
208  struct dictionary *dict
209 CODE:
210  dict_destroy (dict);
211
212
213 int
214 get_var_cnt (dict)
215  struct dictionary *dict
216 CODE:
217  RETVAL = dict_get_var_cnt (dict);
218 OUTPUT:
219 RETVAL
220
221 void
222 set_label (dict, label)
223  struct dictionary *dict
224  char *label
225 CODE:
226  dict_set_label (dict, label);
227
228 void
229 set_documents (dict, docs)
230  struct dictionary *dict
231  char *docs
232 CODE:
233  dict_set_documents (dict, docs);
234
235
236 void
237 add_document (dict, doc)
238  struct dictionary *dict
239  char *doc
240 CODE:
241  dict_add_document_line (dict, doc);
242
243
244 void
245 clear_documents (dict)
246  struct dictionary *dict
247 CODE:
248  dict_clear_documents (dict);
249
250
251 void
252 set_weight (dict, var)
253  struct dictionary *dict
254  struct variable *var
255 CODE:
256  dict_set_weight (dict, var);
257
258
259 struct variable *
260 pxs_get_variable (dict, idx)
261  struct dictionary *dict
262  SV *idx
263 INIT:
264  SV *errstr = get_sv("PSPP::errstr", TRUE);
265  sv_setpv (errstr, "");
266  if ( SvIV (idx) >= dict_get_var_cnt (dict))
267   {
268     sv_setpv (errstr, "The dictionary doesn't have that many variables.");
269     XSRETURN_UNDEF;
270   }
271 CODE:
272  RETVAL = dict_get_var (dict, SvIV (idx));
273  OUTPUT:
274 RETVAL
275
276 MODULE = PSPP           PACKAGE = PSPP::Var
277
278
279 struct variable *
280 pxs_dict_create_var (dict, name, ip_fmt)
281  struct dictionary * dict
282  char *name
283  input_format ip_fmt
284 INIT:
285  SV *errstr = get_sv("PSPP::errstr", TRUE);
286  sv_setpv (errstr, "");
287  if ( ! var_is_plausible_name (name, false))
288   {
289     sv_setpv (errstr, "The variable name is not valid.");
290     XSRETURN_UNDEF;
291   }
292 CODE:
293  struct fmt_spec op_fmt;
294
295  struct variable *v;
296  op_fmt = fmt_for_output_from_input (&ip_fmt);
297  v = dict_create_var (dict, name,
298         fmt_is_string (op_fmt.type) ? op_fmt.w : 0);
299  if ( NULL == v )
300   {
301     sv_setpv (errstr, "The variable could not be created (probably already exists).");
302     XSRETURN_UNDEF;
303   }
304  var_set_both_formats (v, &op_fmt);
305  var_set_input_format (v, ip_fmt);
306  RETVAL = v;
307 OUTPUT:
308  RETVAL
309
310
311 int
312 set_missing_values (var, v1, ...)
313  struct variable *var;
314  SV *v1;
315 INIT:
316  int i;
317  union value val[3];
318
319  if ( items > 4 )
320   croak ("No more than 3 missing values are permitted");
321
322  for (i = 0; i < items - 1; ++i)
323    scalar_to_value (&val[i], ST(i+1), var);
324 CODE:
325  struct missing_values mv;
326  mv_init (&mv, var_get_width (var));
327  for (i = 0 ; i < items - 1; ++i )
328    mv_add_value (&mv, &val[i]);
329  var_set_missing_values (var, &mv);
330
331
332 void
333 set_label (var, label)
334  struct variable *var;
335  char *label
336 CODE:
337   var_set_label (var, label);
338
339
340 void
341 clear_value_labels (var)
342  struct variable *var;
343 CODE:
344  var_clear_value_labels (var);
345
346 void
347 pxs_set_write_format (var, fmt)
348  struct variable *var
349  output_format fmt
350 CODE:
351  var_set_write_format (var, &fmt);
352
353
354 void
355 pxs_set_print_format (var, fmt)
356  struct variable *var
357  output_format fmt
358 CODE:
359  var_set_print_format (var, &fmt);
360
361 void
362 pxs_set_output_format (var, fmt)
363  struct variable *var
364  output_format fmt
365 CODE:
366  var_set_both_formats (var, &fmt);
367
368
369 int
370 add_value_label (var, key, label)
371  struct variable *var
372  SV *key
373  char *label
374 INIT:
375  SV *errstr = get_sv("PSPP::errstr", TRUE);
376  sv_setpv (errstr, "");
377 CODE:
378  union value the_value;
379
380  if ( var_is_numeric (var))
381  {
382   if ( ! looks_like_number (key))
383     {
384       sv_setpv (errstr, "Cannot add label with string key to a numeric variable");
385       XSRETURN_IV (0);
386     }
387   the_value.f = SvNV (key);
388  }
389  else
390  {
391    if ( var_is_long_string (var) )
392      {
393       sv_setpv (errstr, "Cannot add label to a long string variable");
394       XSRETURN_IV (0);
395      }
396   strncpy (the_value.s, SvPV_nolen(key), MAX_SHORT_STRING);
397  }
398  if (! var_add_value_label (var, &the_value, label) )
399  {
400    sv_setpv (errstr, "Something went wrong");
401    XSRETURN_IV (0);
402  }
403  XSRETURN_IV (1);
404
405
406
407 const char *
408 get_name (var)
409  struct variable * var
410 CODE:
411  RETVAL = var_get_name (var);
412  OUTPUT:
413 RETVAL
414
415
416 const char *
417 get_label (var)
418  struct variable * var
419 CODE:
420  RETVAL = var_get_label (var);
421  OUTPUT:
422 RETVAL
423
424
425 SV *
426 get_value_labels (var)
427  struct variable *var
428 CODE:
429  HV *labelhash = (HV *) sv_2mortal ((SV *) newHV());
430  struct val_lab *vl;
431  struct val_labs_iterator *viter = NULL;
432  const struct val_labs *labels = var_get_value_labels (var);
433
434  if ( labels )
435    {
436      for (vl = val_labs_first (labels, &viter);
437           vl;
438           vl = val_labs_next (labels, &viter))
439        {
440          SV *sv = value_to_scalar (&vl->value, var);
441          STRLEN len;
442          const char *s = SvPV (sv, len);
443          hv_store (labelhash, s, len, newSVpv (vl->label, 0), 0);
444        }
445    }
446
447  RETVAL = newRV ((SV *) labelhash);
448  OUTPUT:
449 RETVAL
450
451
452
453 MODULE = PSPP           PACKAGE = PSPP::Sysfile
454
455
456 struct sysfile_info *
457 pxs_create_sysfile (name, dict, opts_hr)
458  char *name
459  struct dictionary *dict
460  SV *opts_hr
461 INIT:
462  struct sfm_write_options opts;
463  if (!SvROK (opts_hr))
464   {
465     opts = sfm_writer_default_options ();
466   }
467  else
468   {
469     HV *opt_h = (HV *) SvRV (opts_hr);
470     SV** readonly = hv_fetch(opt_h, "readonly", 8, 0);
471     SV** compress = hv_fetch(opt_h, "compress", 8, 0);
472     SV** version = hv_fetch(opt_h, "version", 7, 0);
473
474     opts.create_writeable = readonly ? ! SvIV (*readonly) : true;
475     opts.compress = compress ? SvIV (*compress) : false;
476     opts.version = version ? SvIV (*version) : 3 ;
477   }
478 CODE:
479  struct file_handle *fh =
480   fh_create_file (NULL, name, fh_default_properties () );
481  struct sysfile_info *sfi = xmalloc (sizeof (*sfi));
482  sfi->writer = sfm_open_writer (fh, dict, opts);
483  sfi->dict = dict;
484  sfi->opened = true;
485  
486  RETVAL = sfi;
487  OUTPUT:
488 RETVAL
489
490 int
491 close (sfi)
492  struct sysfile_info *sfi
493 CODE:
494  RETVAL = sysfile_close (sfi);
495 OUTPUT:
496  RETVAL
497
498 void
499 DESTROY (sfi)
500  struct sysfile_info *sfi
501 CODE:
502  sysfile_close (sfi);
503  free (sfi);
504
505 int
506 append_case (sfi, ccase)
507  struct sysfile_info *sfi
508  SV *ccase
509 INIT:
510  SV *errstr = get_sv("PSPP::errstr", TRUE);
511  sv_setpv (errstr, "");
512  if ( (!SvROK(ccase)))
513   {
514     XSRETURN_UNDEF;
515   }
516 CODE:
517  int i = 0;
518  AV *av_case = (AV*) SvRV (ccase);
519
520  const struct variable **vv;
521  size_t nv;
522  struct ccase c;
523  SV *sv;
524
525  if ( av_len (av_case) >= dict_get_var_cnt (sfi->dict))
526    XSRETURN_UNDEF;
527
528  case_create (&c, dict_get_next_value_idx (sfi->dict));
529
530  dict_get_vars (sfi->dict, &vv, &nv, 1u << DC_ORDINARY | 1u << DC_SYSTEM);
531
532  for (sv = av_shift (av_case); SvOK (sv);  sv = av_shift (av_case))
533  {
534     const struct variable *v = vv[i++];
535     const struct fmt_spec *ifmt = var_get_aux (v);
536
537     /* If an input format has been set, then use it.
538        Otherwise just convert the raw value.
539     */
540     if ( ifmt )
541       {
542         struct substring ss = ss_cstr (SvPV_nolen (sv));
543         if ( ! data_in (ss, LEGACY_NATIVE, ifmt->type, 0, 0, 0,
544                         case_data_rw (&c, v),
545                         var_get_width (v)) )
546           {
547             RETVAL = 0;
548             goto finish;
549           }
550       }
551     else
552       {
553         scalar_to_value (case_data_rw (&c, v), sv, v);
554       }
555  }
556
557  /* The remaining variables must be sysmis or blank string */
558  while (i < dict_get_var_cnt (sfi->dict))
559  {
560    const struct variable *v = vv[i++];
561    union value *val = case_data_rw (&c, v);
562    if ( var_is_numeric (v))
563         val->f = SYSMIS;
564    else
565         memset (val->s, ' ', var_get_width (v));
566  }
567  RETVAL = casewriter_write (sfi->writer, &c);
568  finish:
569 // case_destroy (&c);
570  free (vv);
571 OUTPUT:
572  RETVAL
573
574
575 \f
576
577 MODULE = PSPP           PACKAGE = PSPP::Reader
578
579 struct sysreader_info *
580 pxs_open_sysfile (name)
581  char * name
582 CODE:
583  struct casereader *reader;
584  struct sysreader_info *sri = NULL;
585  struct file_handle *fh =
586          fh_create_file (NULL, name, fh_default_properties () );
587
588  sri = xmalloc (sizeof (*sri));
589  sri->reader = sfm_open_reader (fh, &sri->dict, &sri->opts);
590
591  if ( NULL == sri->reader)
592  {
593    free (sri);
594    sri = NULL;
595  }
596
597  RETVAL = sri;
598  OUTPUT:
599 RETVAL
600
601
602 struct dictionary *
603 pxs_get_dict (reader)
604  struct sysreader_info *reader;
605 CODE:
606  RETVAL = reader->dict;
607  OUTPUT:
608 RETVAL
609
610
611 SV *
612 get_next_case (sfr)
613  struct sysreader_info *sfr;
614 CODE:
615  struct ccase c;
616
617  if (! casereader_read (sfr->reader, &c))
618  {
619   RETVAL = 0;
620  }
621  else
622  {
623   int v;
624   AV *av_case = (AV *) sv_2mortal ((SV *) newAV());
625
626   for (v = 0; v < dict_get_var_cnt (sfr->dict); ++v )
627     {
628       const struct variable *var = dict_get_var (sfr->dict, v);
629       const union value *val = case_data (&c, var);
630
631       av_push (av_case, value_to_scalar (val, var));
632     }
633
634   case_destroy (&c);
635   RETVAL = newRV ((SV *) av_case);
636  }
637 OUTPUT:
638  RETVAL
639