a2d963188ac949d64fa5e1ea9829d8f59375411a
[pspp] / src / language / xforms / recode.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2009, 2010, 2011 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU 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, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include <ctype.h>
20 #include <math.h>
21 #include <stdlib.h>
22
23 #include "data/case.h"
24 #include "data/data-in.h"
25 #include "data/dataset.h"
26 #include "data/dictionary.h"
27 #include "data/format.h"
28 #include "data/transformations.h"
29 #include "data/variable.h"
30 #include "language/command.h"
31 #include "language/lexer/lexer.h"
32 #include "language/lexer/value-parser.h"
33 #include "language/lexer/variable-parser.h"
34 #include "libpspp/assertion.h"
35 #include "libpspp/cast.h"
36 #include "libpspp/compiler.h"
37 #include "libpspp/i18n.h"
38 #include "libpspp/message.h"
39 #include "libpspp/pool.h"
40 #include "libpspp/str.h"
41
42 #include "gl/xalloc.h"
43
44 #include "gettext.h"
45 #define _(msgid) gettext (msgid)
46 \f
47 /* Definitions. */
48
49 /* Type of source value for RECODE. */
50 enum map_in_type
51   {
52     MAP_SINGLE,                 /* Specific value. */
53     MAP_RANGE,                  /* Range of values. */
54     MAP_SYSMIS,                 /* System missing value. */
55     MAP_MISSING,                /* Any missing value. */
56     MAP_ELSE,                   /* Any value. */
57     MAP_CONVERT                 /* "123" => 123. */
58   };
59
60 /* Describes input values to be mapped. */
61 struct map_in
62   {
63     enum map_in_type type;      /* One of MAP_*. */
64     union value x, y;           /* Source values. */
65   };
66
67 /* Describes the value used as output from a mapping. */
68 struct map_out
69   {
70     bool copy_input;            /* If true, copy input to output. */
71     union value value;          /* If copy_input false, recoded value. */
72     int width;                  /* If copy_input false, output value width. */
73   };
74
75 /* Describes how to recode a single value or range of values into a
76    single value.  */
77 struct mapping
78   {
79     struct map_in in;           /* Input values. */
80     struct map_out out;         /* Output value. */
81   };
82
83 /* RECODE transformation. */
84 struct recode_trns
85   {
86     struct pool *pool;
87
88     /* Variable types, for convenience. */
89     enum val_type src_type;     /* src_vars[*] type. */
90     enum val_type dst_type;     /* dst_vars[*] type. */
91
92     /* Variables. */
93     const struct variable **src_vars;   /* Source variables. */
94     const struct variable **dst_vars;   /* Destination variables. */
95     const struct dictionary *dst_dict;  /* Dictionary of dst_vars */
96     char **dst_names;           /* Name of dest variables, if they're new. */
97     size_t n_vars;             /* Number of variables. */
98
99     /* Mappings. */
100     struct mapping *mappings;   /* Value mappings. */
101     size_t n_maps;              /* Number of mappings. */
102     int max_src_width;          /* Maximum width of src_vars[*]. */
103     int max_dst_width;          /* Maximum width of any map_out in mappings. */
104   };
105
106 static bool parse_src_vars (struct lexer *, struct recode_trns *, const struct dictionary *dict);
107 static bool parse_mappings (struct lexer *, struct recode_trns *,
108                             const char *dict_encoding);
109 static bool parse_dst_vars (struct lexer *, struct recode_trns *, const struct dictionary *dict);
110
111 static void add_mapping (struct recode_trns *,
112                          size_t *map_allocated, const struct map_in *);
113
114 static bool parse_map_in (struct lexer *lexer, struct map_in *, struct pool *,
115                           enum val_type src_type, size_t max_src_width,
116                           const char *dict_encoding);
117 static void set_map_in_generic (struct map_in *, enum map_in_type);
118 static void set_map_in_num (struct map_in *, enum map_in_type, double, double);
119 static void set_map_in_str (struct map_in *, struct pool *,
120                             struct substring, size_t width,
121                             const char *dict_encoding);
122
123 static bool parse_map_out (struct lexer *lexer, struct pool *, struct map_out *);
124 static void set_map_out_num (struct map_out *, double);
125 static void set_map_out_str (struct map_out *, struct pool *,
126                              struct substring);
127
128 static bool enlarge_dst_widths (struct recode_trns *);
129 static void create_dst_vars (struct recode_trns *, struct dictionary *);
130
131 static trns_proc_func recode_trns_proc;
132 static trns_free_func recode_trns_free;
133 \f
134 /* Parser. */
135
136 /* Parses the RECODE transformation. */
137 int
138 cmd_recode (struct lexer *lexer, struct dataset *ds)
139 {
140   do
141     {
142       struct dictionary *dict = dataset_dict (ds);
143       struct recode_trns *trns
144         = pool_create_container (struct recode_trns, pool);
145
146       /* Parse source variable names,
147          then input to output mappings,
148          then destintation variable names. */
149       if (!parse_src_vars (lexer, trns, dict)
150           || !parse_mappings (lexer, trns, dict_get_encoding (dict))
151           || !parse_dst_vars (lexer, trns, dict))
152         {
153           recode_trns_free (trns);
154           return CMD_FAILURE;
155         }
156
157       /* Ensure that all the output strings are at least as wide
158          as the widest destination variable. */
159       if (trns->dst_type == VAL_STRING)
160         {
161           if (! enlarge_dst_widths (trns))
162             {
163               recode_trns_free (trns);
164               return CMD_FAILURE;
165             }
166         }
167
168       /* Create destination variables, if needed.
169          This must be the final step; otherwise we'd have to
170          delete destination variables on failure. */
171       trns->dst_dict = dict;
172       if (trns->src_vars != trns->dst_vars)
173         create_dst_vars (trns, dict);
174
175       /* Done. */
176       add_transformation (ds,
177                           recode_trns_proc, recode_trns_free, trns);
178     }
179   while (lex_match (lexer, T_SLASH));
180
181   return CMD_SUCCESS;
182 }
183
184 /* Parses a set of variables to recode into TRNS->src_vars and
185    TRNS->n_vars.  Sets TRNS->src_type.  Returns true if
186    successful, false on parse error. */
187 static bool
188 parse_src_vars (struct lexer *lexer,
189                 struct recode_trns *trns, const struct dictionary *dict)
190 {
191   if (!parse_variables_const (lexer, dict, &trns->src_vars, &trns->n_vars,
192                         PV_SAME_TYPE))
193     return false;
194   pool_register (trns->pool, free, trns->src_vars);
195   trns->src_type = var_get_type (trns->src_vars[0]);
196   return true;
197 }
198
199 /* Parses a set of mappings, which take the form (input=output),
200    into TRNS->mappings and TRNS->n_maps.  Sets TRNS->dst_type.
201    Returns true if successful, false on parse error. */
202 static bool
203 parse_mappings (struct lexer *lexer, struct recode_trns *trns,
204                 const char *dict_encoding)
205 {
206   size_t map_allocated;
207   bool have_dst_type;
208   size_t i;
209
210   /* Find length of longest source variable. */
211   trns->max_src_width = var_get_width (trns->src_vars[0]);
212   for (i = 1; i < trns->n_vars; i++)
213     {
214       size_t var_width = var_get_width (trns->src_vars[i]);
215       if (var_width > trns->max_src_width)
216         trns->max_src_width = var_width;
217     }
218
219   /* Parse the mappings in parentheses. */
220   trns->mappings = NULL;
221   trns->n_maps = 0;
222   map_allocated = 0;
223   have_dst_type = false;
224   if (!lex_force_match (lexer, T_LPAREN))
225     return false;
226   do
227     {
228       enum val_type dst_type;
229
230       if (!lex_match_id (lexer, "CONVERT"))
231         {
232           struct map_out out;
233           size_t first_map_idx;
234           size_t i;
235
236           first_map_idx = trns->n_maps;
237
238           /* Parse source specifications. */
239           do
240             {
241               struct map_in in;
242
243               if (!parse_map_in (lexer, &in, trns->pool,
244                                  trns->src_type, trns->max_src_width,
245                                  dict_encoding))
246                 return false;
247               add_mapping (trns, &map_allocated, &in);
248               lex_match (lexer, T_COMMA);
249             }
250           while (!lex_match (lexer, T_EQUALS));
251
252           if (!parse_map_out (lexer, trns->pool, &out))
253             return false;
254
255           if (out.copy_input)
256             dst_type = trns->src_type;
257           else
258             dst_type = val_type_from_width (out.width);
259           if (have_dst_type && dst_type != trns->dst_type)
260             {
261               msg (SE, _("Inconsistent target variable types.  "
262                          "Target variables "
263                          "must be all numeric or all string."));
264               return false;
265             }
266
267           for (i = first_map_idx; i < trns->n_maps; i++)
268             trns->mappings[i].out = out;
269         }
270       else
271         {
272           /* Parse CONVERT as a special case. */
273           struct map_in in;
274           set_map_in_generic (&in, MAP_CONVERT);
275           add_mapping (trns, &map_allocated, &in);
276           set_map_out_num (&trns->mappings[trns->n_maps - 1].out, 0.0);
277
278           dst_type = VAL_NUMERIC;
279           if (trns->src_type != VAL_STRING
280               || (have_dst_type && trns->dst_type != VAL_NUMERIC))
281             {
282               msg (SE, _("CONVERT requires string input values and "
283                          "numeric output values."));
284               return false;
285             }
286         }
287       trns->dst_type = dst_type;
288       have_dst_type = true;
289
290       if (!lex_force_match (lexer, T_RPAREN))
291         return false;
292     }
293   while (lex_match (lexer, T_LPAREN));
294
295   return true;
296 }
297
298 /* Parses a mapping input value into IN, allocating memory from
299    POOL.  The source value type must be provided as SRC_TYPE and,
300    if string, the maximum width of a string source variable must
301    be provided in MAX_SRC_WIDTH.  Returns true if successful,
302    false on parse error. */
303 static bool
304 parse_map_in (struct lexer *lexer, struct map_in *in, struct pool *pool,
305               enum val_type src_type, size_t max_src_width,
306               const char *dict_encoding)
307 {
308
309   if (lex_match_id (lexer, "ELSE"))
310     set_map_in_generic (in, MAP_ELSE);
311   else if (src_type == VAL_NUMERIC)
312     {
313       if (lex_match_id (lexer, "MISSING"))
314         set_map_in_generic (in, MAP_MISSING);
315       else if (lex_match_id (lexer, "SYSMIS"))
316         set_map_in_generic (in, MAP_SYSMIS);
317       else
318         {
319           double x, y;
320           if (!parse_num_range (lexer, &x, &y, NULL))
321             return false;
322           set_map_in_num (in, x == y ? MAP_SINGLE : MAP_RANGE, x, y);
323         }
324     }
325   else
326     {
327       if (lex_match_id (lexer, "MISSING"))
328         set_map_in_generic (in, MAP_MISSING);
329       else if (!lex_force_string (lexer))
330         return false;
331       else
332         {
333           set_map_in_str (in, pool, lex_tokss (lexer), max_src_width,
334                           dict_encoding);
335           lex_get (lexer);
336           if (lex_token (lexer) == T_ID
337               && lex_id_match (ss_cstr ("THRU"), lex_tokss (lexer)))
338             {
339               msg (SE, _("%s is not allowed with string variables."), "THRU");
340               return false;
341             }
342         }
343     }
344
345   return true;
346 }
347
348 /* Adds IN to the list of mappings in TRNS.
349    MAP_ALLOCATED is the current number of allocated mappings,
350    which is updated as needed. */
351 static void
352 add_mapping (struct recode_trns *trns,
353              size_t *map_allocated, const struct map_in *in)
354 {
355   struct mapping *m;
356   if (trns->n_maps >= *map_allocated)
357     trns->mappings = pool_2nrealloc (trns->pool, trns->mappings,
358                                      map_allocated,
359                                      sizeof *trns->mappings);
360   m = &trns->mappings[trns->n_maps++];
361   m->in = *in;
362 }
363
364 /* Sets IN as a mapping of the given TYPE. */
365 static void
366 set_map_in_generic (struct map_in *in, enum map_in_type type)
367 {
368   in->type = type;
369 }
370
371 /* Sets IN as a numeric mapping of the given TYPE,
372    with X and Y as the two numeric values. */
373 static void
374 set_map_in_num (struct map_in *in, enum map_in_type type, double x, double y)
375 {
376   in->type = type;
377   in->x.f = x;
378   in->y.f = y;
379 }
380
381 /* Sets IN as a string mapping, with STRING as the string,
382    allocated from POOL.  The string is padded with spaces on the
383    right to WIDTH characters long. */
384 static void
385 set_map_in_str (struct map_in *in, struct pool *pool,
386                 struct substring string, size_t width,
387                 const char *dict_encoding)
388 {
389   char *s = recode_string (dict_encoding, "UTF-8",
390                            ss_data (string), ss_length (string));
391   in->type = MAP_SINGLE;
392   value_init_pool (pool, &in->x, width);
393   value_copy_buf_rpad (&in->x, width,
394                        CHAR_CAST (uint8_t *, s), strlen (s), ' ');
395   free (s);
396 }
397
398 /* Parses a mapping output value into OUT, allocating memory from
399    POOL.  Returns true if successful, false on parse error. */
400 static bool
401 parse_map_out (struct lexer *lexer, struct pool *pool, struct map_out *out)
402 {
403   if (lex_is_number (lexer))
404     {
405       set_map_out_num (out, lex_number (lexer));
406       lex_get (lexer);
407     }
408   else if (lex_match_id (lexer, "SYSMIS"))
409     set_map_out_num (out, SYSMIS);
410   else if (lex_is_string (lexer))
411     {
412       set_map_out_str (out, pool, lex_tokss (lexer));
413       lex_get (lexer);
414     }
415   else if (lex_match_id (lexer, "COPY"))
416     {
417       out->copy_input = true;
418       out->width = 0;
419     }
420   else
421     {
422       lex_error (lexer, _("expecting output value"));
423       return false;
424     }
425   return true;
426 }
427
428 /* Sets OUT as a numeric mapping output with the given VALUE. */
429 static void
430 set_map_out_num (struct map_out *out, double value)
431 {
432   out->copy_input = false;
433   out->value.f = value;
434   out->width = 0;
435 }
436
437 /* Sets OUT as a string mapping output with the given VALUE. */
438 static void
439 set_map_out_str (struct map_out *out, struct pool *pool,
440                  const struct substring value)
441 {
442   const char *string = ss_data (value);
443   size_t length = ss_length (value);
444
445   if (length == 0)
446     {
447       /* A length of 0 will yield a numeric value, which is not
448          what we want. */
449       string = " ";
450       length = 1;
451     }
452
453   out->copy_input = false;
454   value_init_pool (pool, &out->value, length);
455   memcpy (out->value.s, string, length);
456   out->width = length;
457 }
458
459 /* Parses a set of target variables into TRNS->dst_vars and
460    TRNS->dst_names. */
461 static bool
462 parse_dst_vars (struct lexer *lexer, struct recode_trns *trns,
463                 const struct dictionary *dict)
464 {
465   size_t i;
466
467   if (lex_match_id (lexer, "INTO"))
468     {
469       size_t n_names;
470       size_t i;
471
472       if (!parse_mixed_vars_pool (lexer, dict, trns->pool,
473                                   &trns->dst_names, &n_names,
474                                   PV_NONE))
475         return false;
476
477       if (n_names != trns->n_vars)
478         {
479           msg (SE, _("%zu variable(s) cannot be recoded into "
480                      "%zu variable(s).  Specify the same number "
481                      "of variables as source and target variables."),
482                trns->n_vars, n_names);
483           return false;
484         }
485
486       trns->dst_vars = pool_nalloc (trns->pool,
487                                     trns->n_vars, sizeof *trns->dst_vars);
488       for (i = 0; i < trns->n_vars; i++)
489         {
490           const struct variable *v;
491           v = trns->dst_vars[i] = dict_lookup_var (dict, trns->dst_names[i]);
492           if (v == NULL && trns->dst_type == VAL_STRING)
493             {
494               msg (SE, _("There is no variable named "
495                          "%s.  (All string variables specified "
496                          "on INTO must already exist.  Use the "
497                          "STRING command to create a string "
498                          "variable.)"),
499                    trns->dst_names[i]);
500               return false;
501             }
502         }
503
504     }
505   else
506     {
507       trns->dst_vars = trns->src_vars;
508       if (trns->src_type != trns->dst_type)
509         {
510           msg (SE, _("INTO is required with %s input values "
511                      "and %s output values."),
512                trns->src_type == VAL_NUMERIC ? _("numeric") : _("string"),
513                trns->dst_type == VAL_NUMERIC ? _("numeric") : _("string"));
514           return false;
515         }
516     }
517
518   for (i = 0; i < trns->n_vars; i++)
519     {
520       const struct variable *v = trns->dst_vars[i];
521       if (v != NULL && var_get_type (v) != trns->dst_type)
522         {
523           msg (SE, _("Type mismatch.  Cannot store %s data in "
524                      "%s variable %s."),
525                trns->dst_type == VAL_STRING ? _("string") : _("numeric"),
526                var_is_alpha (v) ? _("string") : _("numeric"),
527                var_get_name (v));
528           return false;
529         }
530     }
531
532   return true;
533 }
534
535 /* Ensures that all the output values in TRNS are as wide as the
536    widest destination variable. */
537 static bool
538 enlarge_dst_widths (struct recode_trns *trns)
539 {
540   size_t i;
541   const struct variable *narrow_var = NULL;
542   int min_dst_width = INT_MAX;
543   trns->max_dst_width = 0;
544
545   for (i = 0; i < trns->n_vars; i++)
546     {
547       const struct variable *v = trns->dst_vars[i];
548       if (var_get_width (v) > trns->max_dst_width)
549         trns->max_dst_width = var_get_width (v);
550
551       if (var_get_width (v) < min_dst_width)
552         {
553           min_dst_width = var_get_width (v);
554           narrow_var = v;
555         }
556     }
557
558   for (i = 0; i < trns->n_maps; i++)
559     {
560       struct map_out *out = &trns->mappings[i].out;
561       if (!out->copy_input)
562         {
563           if (out->width > min_dst_width)
564             {
565               msg (ME,
566                    _("Cannot recode because the variable %s would require a width of %d bytes or greater, but it has a width of only %d bytes."),
567                    var_get_name (narrow_var), out->width, min_dst_width);
568               return false;
569             }
570
571           value_resize_pool (trns->pool, &out->value,
572                              out->width, trns->max_dst_width);
573         }
574     }
575
576   return true;
577 }
578
579 /* Creates destination variables that don't already exist. */
580 static void
581 create_dst_vars (struct recode_trns *trns, struct dictionary *dict)
582 {
583   size_t i;
584
585   for (i = 0; i < trns->n_vars; i++)
586     {
587       const struct variable **var = &trns->dst_vars[i];
588       const char *name = trns->dst_names[i];
589
590       *var = dict_lookup_var (dict, name);
591       if (*var == NULL)
592         *var = dict_create_var_assert (dict, name, 0);
593       assert (var_get_type (*var) == trns->dst_type);
594     }
595 }
596 \f
597 /* Data transformation. */
598
599 /* Returns the output mapping in TRNS for an input of VALUE on
600    variable V, or a null pointer if there is no mapping. */
601 static const struct map_out *
602 find_src_numeric (struct recode_trns *trns, double value, const struct variable *v)
603 {
604   struct mapping *m;
605
606   for (m = trns->mappings; m < trns->mappings + trns->n_maps; m++)
607     {
608       const struct map_in *in = &m->in;
609       const struct map_out *out = &m->out;
610       bool match;
611
612       switch (in->type)
613         {
614         case MAP_SINGLE:
615           match = value == in->x.f;
616           break;
617         case MAP_MISSING:
618           match = var_is_num_missing (v, value, MV_ANY);
619           break;
620         case MAP_RANGE:
621           match = value >= in->x.f && value <= in->y.f;
622           break;
623         case MAP_SYSMIS:
624           match = value == SYSMIS;
625           break;
626         case MAP_ELSE:
627           match = true;
628           break;
629         default:
630           NOT_REACHED ();
631         }
632
633       if (match)
634         return out;
635     }
636
637   return NULL;
638 }
639
640 /* Returns the output mapping in TRNS for an input of VALUE with
641    the given WIDTH, or a null pointer if there is no mapping. */
642 static const struct map_out *
643 find_src_string (struct recode_trns *trns, const uint8_t *value,
644                  const struct variable *src_var)
645 {
646   const char *encoding = dict_get_encoding (trns->dst_dict);
647   int width = var_get_width (src_var);
648   struct mapping *m;
649
650   for (m = trns->mappings; m < trns->mappings + trns->n_maps; m++)
651     {
652       const struct map_in *in = &m->in;
653       struct map_out *out = &m->out;
654       bool match;
655
656       switch (in->type)
657         {
658         case MAP_SINGLE:
659           match = !memcmp (value, in->x.s, width);
660           break;
661         case MAP_ELSE:
662           match = true;
663           break;
664         case MAP_CONVERT:
665           {
666             union value uv;
667             char *error;
668
669             error = data_in (ss_buffer (CHAR_CAST_BUG (char *, value), width),
670                              C_ENCODING, FMT_F, settings_get_fmt_settings (),
671                              &uv, 0, encoding);
672             match = error == NULL;
673             free (error);
674
675             out->value.f = uv.f;
676             break;
677           }
678         case MAP_MISSING:
679           match = var_is_str_missing (src_var, value, MV_ANY);
680           break;
681         default:
682           NOT_REACHED ();
683         }
684
685       if (match)
686         return out;
687     }
688
689   return NULL;
690 }
691
692 /* Performs RECODE transformation. */
693 static int
694 recode_trns_proc (void *trns_, struct ccase **c, casenumber case_idx UNUSED)
695 {
696   struct recode_trns *trns = trns_;
697   size_t i;
698
699   *c = case_unshare (*c);
700   for (i = 0; i < trns->n_vars; i++)
701     {
702       const struct variable *src_var = trns->src_vars[i];
703       const struct variable *dst_var = trns->dst_vars[i];
704       const struct map_out *out;
705
706       if (trns->src_type == VAL_NUMERIC)
707         out = find_src_numeric (trns, case_num (*c, src_var), src_var);
708       else
709         out = find_src_string (trns, case_str (*c, src_var), src_var);
710
711       if (trns->dst_type == VAL_NUMERIC)
712         {
713           double *dst = case_num_rw (*c, dst_var);
714           if (out != NULL)
715             *dst = !out->copy_input ? out->value.f : case_num (*c, src_var);
716           else if (trns->src_vars != trns->dst_vars)
717             *dst = SYSMIS;
718         }
719       else
720         {
721           char *dst = CHAR_CAST_BUG (char *, case_str_rw (*c, dst_var));
722           if (out != NULL)
723             {
724               if (!out->copy_input)
725                 memcpy (dst, out->value.s, var_get_width (dst_var));
726               else if (trns->src_vars != trns->dst_vars)
727                 {
728                   union value *dst_data = case_data_rw (*c, dst_var);
729                   const union value *src_data = case_data (*c, src_var);
730                   value_copy_rpad (dst_data, var_get_width (dst_var),
731                                    src_data, var_get_width (src_var), ' ');
732                 }
733             }
734           else if (trns->src_vars != trns->dst_vars)
735             memset (dst, ' ', var_get_width (dst_var));
736         }
737     }
738
739   return TRNS_CONTINUE;
740 }
741
742 /* Frees a RECODE transformation. */
743 static bool
744 recode_trns_free (void *trns_)
745 {
746   struct recode_trns *trns = trns_;
747   pool_destroy (trns->pool);
748   return true;
749 }