New subroutine PSPP::Dict::get_var_by_name
[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
277 struct variable *
278 pxs_get_var_by_name (dict, name)
279  struct dictionary *dict
280  const char *name
281 INIT:
282  SV *errstr = get_sv("PSPP::errstr", TRUE);
283  sv_setpv (errstr, "");
284 CODE:
285  struct variable *var = dict_lookup_var (dict, name);
286  if ( ! var )
287       sv_setpv (errstr, "No such variable.");
288  RETVAL = var;
289  OUTPUT:
290 RETVAL
291
292
293 MODULE = PSPP           PACKAGE = PSPP::Var
294
295
296 struct variable *
297 pxs_dict_create_var (dict, name, ip_fmt)
298  struct dictionary * dict
299  char *name
300  input_format ip_fmt
301 INIT:
302  SV *errstr = get_sv("PSPP::errstr", TRUE);
303  sv_setpv (errstr, "");
304  if ( ! var_is_plausible_name (name, false))
305   {
306     sv_setpv (errstr, "The variable name is not valid.");
307     XSRETURN_UNDEF;
308   }
309 CODE:
310  struct fmt_spec op_fmt;
311
312  struct variable *v;
313  op_fmt = fmt_for_output_from_input (&ip_fmt);
314  v = dict_create_var (dict, name,
315         fmt_is_string (op_fmt.type) ? op_fmt.w : 0);
316  if ( NULL == v )
317   {
318     sv_setpv (errstr, "The variable could not be created (probably already exists).");
319     XSRETURN_UNDEF;
320   }
321  var_set_both_formats (v, &op_fmt);
322  var_set_input_format (v, ip_fmt);
323  RETVAL = v;
324 OUTPUT:
325  RETVAL
326
327
328 int
329 set_missing_values (var, v1, ...)
330  struct variable *var;
331  SV *v1;
332 INIT:
333  int i;
334  union value val[3];
335
336  if ( items > 4 )
337   croak ("No more than 3 missing values are permitted");
338
339  for (i = 0; i < items - 1; ++i)
340    scalar_to_value (&val[i], ST(i+1), var);
341 CODE:
342  struct missing_values mv;
343  mv_init (&mv, var_get_width (var));
344  for (i = 0 ; i < items - 1; ++i )
345    mv_add_value (&mv, &val[i]);
346  var_set_missing_values (var, &mv);
347
348
349 void
350 set_label (var, label)
351  struct variable *var;
352  char *label
353 CODE:
354   var_set_label (var, label);
355
356
357 void
358 clear_value_labels (var)
359  struct variable *var;
360 CODE:
361  var_clear_value_labels (var);
362
363 void
364 pxs_set_write_format (var, fmt)
365  struct variable *var
366  output_format fmt
367 CODE:
368  var_set_write_format (var, &fmt);
369
370
371 void
372 pxs_set_print_format (var, fmt)
373  struct variable *var
374  output_format fmt
375 CODE:
376  var_set_print_format (var, &fmt);
377
378 void
379 pxs_set_output_format (var, fmt)
380  struct variable *var
381  output_format fmt
382 CODE:
383  var_set_both_formats (var, &fmt);
384
385
386 int
387 add_value_label (var, key, label)
388  struct variable *var
389  SV *key
390  char *label
391 INIT:
392  SV *errstr = get_sv("PSPP::errstr", TRUE);
393  sv_setpv (errstr, "");
394 CODE:
395  union value the_value;
396
397  if ( var_is_numeric (var))
398  {
399   if ( ! looks_like_number (key))
400     {
401       sv_setpv (errstr, "Cannot add label with string key to a numeric variable");
402       XSRETURN_IV (0);
403     }
404   the_value.f = SvNV (key);
405  }
406  else
407  {
408    if ( var_is_long_string (var) )
409      {
410       sv_setpv (errstr, "Cannot add label to a long string variable");
411       XSRETURN_IV (0);
412      }
413   strncpy (the_value.s, SvPV_nolen(key), MAX_SHORT_STRING);
414  }
415  if (! var_add_value_label (var, &the_value, label) )
416  {
417    sv_setpv (errstr, "Something went wrong");
418    XSRETURN_IV (0);
419  }
420  XSRETURN_IV (1);
421
422
423
424 const char *
425 get_name (var)
426  struct variable * var
427 CODE:
428  RETVAL = var_get_name (var);
429  OUTPUT:
430 RETVAL
431
432
433 const char *
434 get_label (var)
435  struct variable * var
436 CODE:
437  RETVAL = var_get_label (var);
438  OUTPUT:
439 RETVAL
440
441
442 SV *
443 get_value_labels (var)
444  struct variable *var
445 CODE:
446  HV *labelhash = (HV *) sv_2mortal ((SV *) newHV());
447  struct val_lab *vl;
448  struct val_labs_iterator *viter = NULL;
449  const struct val_labs *labels = var_get_value_labels (var);
450
451  if ( labels )
452    {
453      for (vl = val_labs_first (labels, &viter);
454           vl;
455           vl = val_labs_next (labels, &viter))
456        {
457          SV *sv = value_to_scalar (&vl->value, var);
458          STRLEN len;
459          const char *s = SvPV (sv, len);
460          hv_store (labelhash, s, len, newSVpv (vl->label, 0), 0);
461        }
462    }
463
464  RETVAL = newRV ((SV *) labelhash);
465  OUTPUT:
466 RETVAL
467
468
469
470 MODULE = PSPP           PACKAGE = PSPP::Sysfile
471
472
473 struct sysfile_info *
474 pxs_create_sysfile (name, dict, opts_hr)
475  char *name
476  struct dictionary *dict
477  SV *opts_hr
478 INIT:
479  struct sfm_write_options opts;
480  if (!SvROK (opts_hr))
481   {
482     opts = sfm_writer_default_options ();
483   }
484  else
485   {
486     HV *opt_h = (HV *) SvRV (opts_hr);
487     SV** readonly = hv_fetch(opt_h, "readonly", 8, 0);
488     SV** compress = hv_fetch(opt_h, "compress", 8, 0);
489     SV** version = hv_fetch(opt_h, "version", 7, 0);
490
491     opts.create_writeable = readonly ? ! SvIV (*readonly) : true;
492     opts.compress = compress ? SvIV (*compress) : false;
493     opts.version = version ? SvIV (*version) : 3 ;
494   }
495 CODE:
496  struct file_handle *fh =
497   fh_create_file (NULL, name, fh_default_properties () );
498  struct sysfile_info *sfi = xmalloc (sizeof (*sfi));
499  sfi->writer = sfm_open_writer (fh, dict, opts);
500  sfi->dict = dict;
501  sfi->opened = true;
502  
503  RETVAL = sfi;
504  OUTPUT:
505 RETVAL
506
507 int
508 close (sfi)
509  struct sysfile_info *sfi
510 CODE:
511  RETVAL = sysfile_close (sfi);
512 OUTPUT:
513  RETVAL
514
515 void
516 DESTROY (sfi)
517  struct sysfile_info *sfi
518 CODE:
519  sysfile_close (sfi);
520  free (sfi);
521
522 int
523 append_case (sfi, ccase)
524  struct sysfile_info *sfi
525  SV *ccase
526 INIT:
527  SV *errstr = get_sv("PSPP::errstr", TRUE);
528  sv_setpv (errstr, "");
529  if ( (!SvROK(ccase)))
530   {
531     XSRETURN_UNDEF;
532   }
533 CODE:
534  int i = 0;
535  AV *av_case = (AV*) SvRV (ccase);
536
537  const struct variable **vv;
538  size_t nv;
539  struct ccase c;
540  SV *sv;
541
542  if ( av_len (av_case) >= dict_get_var_cnt (sfi->dict))
543    XSRETURN_UNDEF;
544
545  case_create (&c, dict_get_next_value_idx (sfi->dict));
546
547  dict_get_vars (sfi->dict, &vv, &nv, 1u << DC_ORDINARY | 1u << DC_SYSTEM);
548
549  for (sv = av_shift (av_case); SvOK (sv);  sv = av_shift (av_case))
550  {
551     const struct variable *v = vv[i++];
552     const struct fmt_spec *ifmt = var_get_aux (v);
553
554     /* If an input format has been set, then use it.
555        Otherwise just convert the raw value.
556     */
557     if ( ifmt )
558       {
559         struct substring ss = ss_cstr (SvPV_nolen (sv));
560         if ( ! data_in (ss, LEGACY_NATIVE, ifmt->type, 0, 0, 0,
561                         case_data_rw (&c, v),
562                         var_get_width (v)) )
563           {
564             RETVAL = 0;
565             goto finish;
566           }
567       }
568     else
569       {
570         scalar_to_value (case_data_rw (&c, v), sv, v);
571       }
572  }
573
574  /* The remaining variables must be sysmis or blank string */
575  while (i < dict_get_var_cnt (sfi->dict))
576  {
577    const struct variable *v = vv[i++];
578    union value *val = case_data_rw (&c, v);
579    if ( var_is_numeric (v))
580         val->f = SYSMIS;
581    else
582         memset (val->s, ' ', var_get_width (v));
583  }
584  RETVAL = casewriter_write (sfi->writer, &c);
585  finish:
586 // case_destroy (&c);
587  free (vv);
588 OUTPUT:
589  RETVAL
590
591
592 \f
593
594 MODULE = PSPP           PACKAGE = PSPP::Reader
595
596 struct sysreader_info *
597 pxs_open_sysfile (name)
598  char * name
599 CODE:
600  struct casereader *reader;
601  struct sysreader_info *sri = NULL;
602  struct file_handle *fh =
603          fh_create_file (NULL, name, fh_default_properties () );
604
605  sri = xmalloc (sizeof (*sri));
606  sri->reader = sfm_open_reader (fh, &sri->dict, &sri->opts);
607
608  if ( NULL == sri->reader)
609  {
610    free (sri);
611    sri = NULL;
612  }
613
614  RETVAL = sri;
615  OUTPUT:
616 RETVAL
617
618
619 struct dictionary *
620 pxs_get_dict (reader)
621  struct sysreader_info *reader;
622 CODE:
623  RETVAL = reader->dict;
624  OUTPUT:
625 RETVAL
626
627
628 SV *
629 get_next_case (sfr)
630  struct sysreader_info *sfr;
631 CODE:
632  struct ccase c;
633
634  if (! casereader_read (sfr->reader, &c))
635  {
636   RETVAL = 0;
637  }
638  else
639  {
640   int v;
641   AV *av_case = (AV *) sv_2mortal ((SV *) newAV());
642
643   for (v = 0; v < dict_get_var_cnt (sfr->dict); ++v )
644     {
645       const struct variable *var = dict_get_var (sfr->dict, v);
646       const union value *val = case_data (&c, var);
647
648       av_push (av_case, value_to_scalar (val, var));
649     }
650
651   case_destroy (&c);
652   RETVAL = newRV ((SV *) av_case);
653  }
654 OUTPUT:
655  RETVAL
656