b364a1ac3ef2422f06d8ffad0086cbf5f5ad7c8a
[pspp-builds.git] / src / recode.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 #include <config.h>
21 #include "error.h"
22 #include <ctype.h>
23 #include <math.h>
24 #include <stdlib.h>
25 #include "alloc.h"
26 #include "case.h"
27 #include "command.h"
28 #include "dictionary.h"
29 #include "error.h"
30 #include "lexer.h"
31 #include "magic.h"
32 #include "str.h"
33 #include "var.h"
34
35 #include "gettext.h"
36 #define _(msgid) gettext (msgid)
37 \f
38 /* Definitions. */
39
40 /* Type of source value for RECODE. */
41 enum
42   {
43     RCD_END,                    /* sentinel value */
44     RCD_USER,                   /* user-missing => one */
45     RCD_SINGLE,                 /* one => one */
46     RCD_HIGH,                   /* x > a => one */
47     RCD_LOW,                    /* x < b => one */
48     RCD_RANGE,                  /* b < x < a => one */
49     RCD_ELSE,                   /* any but SYSMIS => one */
50     RCD_CONVERT                 /* "123" => 123 */
51   };
52
53 /* Describes how to recode a single value or range of values into a
54    single value.  */
55 struct coding
56   {
57     int type;                   /* RCD_* */
58     union value f1, f2;         /* Describe value or range as src.  Long
59                                    strings are stored in `c'. */
60     union value t;              /* Describes value as dest. Long strings in `c'. */
61   };
62
63 /* Describes how to recode a single variable. */
64 struct rcd_var
65   {
66     struct rcd_var *next;
67
68     unsigned flags;             /* RCD_SRC_* | RCD_DEST_* | RCD_MISC_* */
69
70     struct variable *src;       /* Source variable. */
71     struct variable *dest;      /* Destination variable. */
72     char dest_name[LONG_NAME_LEN + 1];          /* Name of dest variable if we're creating it. */
73
74     int has_sysmis;             /* Do we recode for SYSMIS? */
75     union value sysmis;         /* Coding for SYSMIS (if src is numeric). */
76
77     struct coding *map;         /* Coding for other values. */
78     size_t nmap, mmap;          /* Length of map, max capacity of map. */
79   };
80
81 /* RECODE transformation. */
82 struct recode_trns
83   {
84     struct trns_header h;
85     struct rcd_var *codings;
86   };
87
88 /* What we're recoding from (`src'==`source'). */
89 #define RCD_SRC_ERROR           0000u   /* Bad value for src. */
90 #define RCD_SRC_NUMERIC         0001u   /* Src is numeric. */
91 #define RCD_SRC_STRING          0002u   /* Src is short string. */
92 #define RCD_SRC_MASK            0003u   /* AND mask to isolate src bits. */
93
94 /* What we're recoding to (`dest'==`destination'). */
95 #define RCD_DEST_ERROR          0000u   /* Bad value for dest. */
96 #define RCD_DEST_NUMERIC        0004u   /* Dest is numeric. */
97 #define RCD_DEST_STRING         0010u   /* Dest is short string. */
98 #define RCD_DEST_MASK           0014u   /* AND mask to isolate dest bits. */
99
100 /* Miscellaneous bits. */
101 #define RCD_MISC_CREATE         0020u   /* We create dest var (numeric only) */
102 #define RCD_MISC_DUPLICATE      0040u   /* This var_info has the same MAP
103                                            value as the previous var_info.
104                                            Prevents redundant free()ing. */
105 #define RCD_MISC_MISSING        0100u   /* Encountered MISSING or SYSMIS in
106                                            this input spec. */
107
108 static int parse_dest_spec (struct rcd_var * rcd, union value *v,
109                             size_t *max_dst_width);
110 static int parse_src_spec (struct rcd_var * rcd, int type, size_t max_src_width);
111 static trns_proc_func recode_trns_proc;
112 static trns_free_func recode_trns_free;
113 static double convert_to_double (const char *, int);
114 \f
115 /* Parser. */
116
117 /* Parses the RECODE transformation. */
118 int
119 cmd_recode (void)
120 {
121   size_t i;
122
123   /* Transformation that we're constructing. */
124   struct rcd_var *rcd;
125
126   /* Type of the src variables. */
127   int type;
128
129   /* Length of longest src string. */
130   size_t max_src_width;
131
132   /* Length of longest dest string. */
133   size_t max_dst_width;
134
135   /* For stepping through, constructing the linked list of
136      recodings. */
137   struct rcd_var *iter;
138
139   /* The real transformation, just a wrapper for a list of
140      rcd_var's. */
141   struct recode_trns *trns;
142
143   /* First transformation in the list.  rcd is in this list. */
144   struct rcd_var *head;
145
146   /* Variables in the current part of the recoding. */
147   struct variable **v;
148   size_t nv;
149
150   /* Parses each specification between slashes. */
151   head = rcd = xmalloc (sizeof *rcd);
152   v = NULL;
153   for (;;)
154     {
155       /* Whether we've already encountered a specification for SYSMIS. */
156       int had_sysmis = 0;
157
158       /* Initialize this rcd_var to ensure proper cleanup. */
159       rcd->next = NULL;
160       rcd->map = NULL;
161       rcd->nmap = rcd->mmap = 0;
162       rcd->has_sysmis = 0;
163       rcd->sysmis.f = 0;
164
165       /* Parse variable names. */
166       if (!parse_variables (default_dict, &v, &nv, PV_SAME_TYPE))
167         goto lossage;
168
169       /* Ensure all variables are same type; find length of longest
170          source variable. */
171       type = v[0]->type;
172       max_src_width = v[0]->width;
173
174       if (type == ALPHA)
175         for (i = 0; i < nv; i++)
176           if (v[i]->width > (int) max_src_width)
177             max_src_width = v[i]->width;
178
179       /* Set up flags. */
180       rcd->flags = 0;
181       if (type == NUMERIC)
182         rcd->flags |= RCD_SRC_NUMERIC;
183       else
184         rcd->flags |= RCD_SRC_STRING;
185
186       /* Parse each coding in parentheses. */
187       max_dst_width = 0;
188       if (!lex_force_match ('('))
189         goto lossage;
190       for (;;) 
191         {
192           /* Get the input value (before the `='). */
193           size_t mark = rcd->nmap;
194           int code = parse_src_spec (rcd, type, max_src_width);
195           if (!code)
196             goto lossage;
197
198           /* ELSE is the same as any other input spec except that it
199              precludes later sysmis specifications. */
200           if (code == 3)
201             {
202               had_sysmis = 1;
203               code = 1;
204             }
205
206           /* If keyword CONVERT was specified, there is no output
207              specification.  */
208           if (code == 1)
209             {
210               union value output;
211
212               /* Get the output value (after the `='). */
213               lex_get ();       /* Skip `='. */
214               if (!parse_dest_spec (rcd, &output, &max_dst_width))
215                 goto lossage;
216
217               /* Set the value for SYSMIS if requested and if we don't
218                  already have one. */
219               if ((rcd->flags & RCD_MISC_MISSING) && !had_sysmis)
220                 {
221                   rcd->has_sysmis = 1;
222                   if ((rcd->flags & RCD_DEST_MASK) == RCD_DEST_NUMERIC)
223                     rcd->sysmis.f = output.f;
224                   else
225                     rcd->sysmis.c = xstrdup (output.c);
226                   had_sysmis = 1;
227
228                   rcd->flags &= ~RCD_MISC_MISSING;
229                 }
230
231               /* Since there may be multiple input values for a single
232                  output, the output value need to propagated among all
233                  of them. */
234               if ((rcd->flags & RCD_DEST_MASK) == RCD_DEST_NUMERIC)
235                 for (i = mark; i < rcd->nmap; i++)
236                   rcd->map[i].t.f = output.f;
237               else
238                 {
239                   for (i = mark; i < rcd->nmap; i++)
240                     rcd->map[i].t.c = output.c ? xstrdup (output.c) : NULL;
241                   free (output.c);
242                 }
243             }
244           lex_get ();           /* Skip `)'. */
245           if (!lex_match ('('))
246             break;
247         }
248
249       /* Append sentinel value. */
250       rcd->map[rcd->nmap++].type = RCD_END;
251
252       /* Since multiple variables may use the same recodings, it is
253          necessary to propogate the codings to all of them. */
254       rcd->src = v[0];
255       rcd->dest = v[0];
256       rcd->dest_name[0] = 0;
257       iter = rcd;
258       for (i = 1; i < nv; i++)
259         {
260           iter = iter->next = xmalloc (sizeof *iter);
261           iter->next = NULL;
262           iter->flags = rcd->flags | RCD_MISC_DUPLICATE;
263           iter->src = v[i];
264           iter->dest = v[i];
265           iter->dest_name[0] = 0;
266           iter->has_sysmis = rcd->has_sysmis;
267           iter->sysmis = rcd->sysmis;
268           iter->map = rcd->map;
269         }
270
271       if (lex_match_id ("INTO"))
272         {
273           char **names;
274           size_t nnames;
275
276           int success = 0;
277
278           if (!parse_mixed_vars (&names, &nnames, PV_NONE))
279             goto lossage;
280
281           if (nnames != nv)
282             {
283               for (i = 0; i < nnames; i++)
284                 free (names[i]);
285               free (names);
286               msg (SE, _("%u variable(s) cannot be recoded into "
287                          "%u variable(s).  Specify the same number "
288                          "of variables as input and output variables."),
289                    (unsigned) nv, (unsigned) nnames);
290               goto lossage;
291             }
292
293           if ((rcd->flags & RCD_DEST_MASK) == RCD_DEST_STRING)
294             for (i = 0, iter = rcd; i < nv; i++, iter = iter->next)
295               {
296                 struct variable *v = dict_lookup_var (default_dict, names[i]);
297
298                 if (!v)
299                   {
300                     msg (SE, _("There is no string variable named "
301                                "%s.  (All string variables specified "
302                                "on INTO must already exist.  Use the "
303                                "STRING command to create a string "
304                                "variable.)"),
305                          names[i]);
306                     goto INTO_fail;
307                   }
308                 if (v->type != ALPHA)
309                   {
310                     msg (SE, _("Type mismatch between input and output "
311                                "variables.  Output variable %s is not "
312                                "a string variable, but all the input "
313                                "variables are string variables."),
314                          v->name);
315                     goto INTO_fail;
316                   }
317                 if (v->width > (int) max_dst_width)
318                   max_dst_width = v->width;
319                 iter->dest = v;
320               }
321           else
322             for (i = 0, iter = rcd; i < nv; i++, iter = iter->next)
323               {
324                 struct variable *v = dict_lookup_var (default_dict, names[i]);
325
326                 if (v)
327                   {
328                     if (v->type != NUMERIC)
329                       {
330                         msg (SE, _("Type mismatch after INTO: %s "
331                                    "is not a numeric variable."), v->name);
332                         goto INTO_fail;
333                       }
334                     else
335                       iter->dest = v;
336                   }
337                 else
338                   strcpy (iter->dest_name, names[i]);
339               }
340           success = 1;
341
342           /* Note that regardless of whether we succeed or fail,
343              flow-of-control comes here.  `success' is the important
344              factor.  Ah, if C had garbage collection...  */
345         INTO_fail:
346           for (i = 0; i < nnames; i++)
347             free (names[i]);
348           free (names);
349           if (!success)
350             goto lossage;
351         }
352       else
353         {
354           if (max_src_width > max_dst_width)
355             max_dst_width = max_src_width;
356
357           if ((rcd->flags & RCD_SRC_MASK) == RCD_SRC_NUMERIC
358               && (rcd->flags & RCD_DEST_MASK) != RCD_DEST_NUMERIC)
359             {
360               msg (SE, _("INTO must be used when the input values are "
361                          "numeric and output values are string."));
362               goto lossage;
363             }
364           
365           if ((rcd->flags & RCD_SRC_MASK) != RCD_SRC_NUMERIC
366               && (rcd->flags & RCD_DEST_MASK) == RCD_DEST_NUMERIC)
367             {
368               msg (SE, _("INTO must be used when the input values are "
369                          "string and output values are numeric."));
370               goto lossage;
371             }
372         }
373
374       if ((rcd->flags & RCD_DEST_MASK) == RCD_DEST_STRING)
375         {
376           struct coding *cp;
377
378           for (cp = rcd->map; cp->type != RCD_END; cp++)
379             if (cp->t.c)
380               {
381                 if (strlen (cp->t.c) < max_dst_width)
382                   {
383                     /* The NULL is only really necessary for the
384                        debugging code. */
385                     char *repl = xmalloc (max_dst_width + 1);
386                     str_copy_rpad (repl, max_dst_width + 1, cp->t.c);
387                     free (cp->t.c);
388                     cp->t.c = repl;
389                   }
390                 else
391                   /* The strings are guaranteed to be in order of
392                      nondecreasing length. */
393                   break;
394               }
395           
396         }
397
398       free (v);
399       v = NULL;
400
401       if (!lex_match ('/'))
402         break;
403       while (rcd->next)
404         rcd = rcd->next;
405       rcd = rcd->next = xmalloc (sizeof *rcd);
406     }
407
408   if (token != '.')
409     {
410       lex_error (_("expecting end of command"));
411       goto lossage;
412     }
413
414   for (rcd = head; rcd; rcd = rcd->next)
415     if (rcd->dest_name[0])
416       {
417         rcd->dest = dict_create_var (default_dict, rcd->dest_name, 0);
418         if (!rcd->dest)
419           {
420             /* FIXME: This can fail if a destname is duplicated.
421                We could give an error at parse time but I don't
422                care enough. */
423             rcd->dest = dict_lookup_var_assert (default_dict, rcd->dest_name);
424           }
425       }
426
427   trns = xmalloc (sizeof *trns);
428   trns->h.proc = recode_trns_proc;
429   trns->h.free = recode_trns_free;
430   trns->codings = head;
431   add_transformation ((struct trns_header *) trns);
432
433   return CMD_SUCCESS;
434
435  lossage:
436   free (v);
437   {
438     struct recode_trns t;
439
440     t.codings = head;
441     recode_trns_free ((struct trns_header *) &t);
442     return CMD_FAILURE;
443   }
444 }
445
446 static int
447 parse_dest_spec (struct rcd_var * rcd, union value * v, size_t *max_dst_width)
448 {
449   int flags;
450
451   v->c = NULL;
452
453   if (lex_is_number ())
454     {
455       v->f = tokval;
456       lex_get ();
457       flags = RCD_DEST_NUMERIC;
458     }
459   else if (lex_match_id ("SYSMIS"))
460     {
461       v->f = SYSMIS;
462       flags = RCD_DEST_NUMERIC;
463     }
464   else if (token == T_STRING)
465     {
466       size_t max = *max_dst_width;
467       size_t toklen = ds_length (&tokstr);
468       if (toklen > max)
469         max = toklen;
470       v->c = xmalloc (max + 1);
471       str_copy_rpad (v->c, max + 1, ds_c_str (&tokstr));
472       flags = RCD_DEST_STRING;
473       *max_dst_width = max;
474       lex_get ();
475     }
476   else if (lex_match_id ("COPY"))
477     {
478       if ((rcd->flags & RCD_SRC_MASK) == RCD_SRC_NUMERIC)
479         {
480           flags = RCD_DEST_NUMERIC;
481           v->f = -SYSMIS;
482         }
483       else
484         {
485           flags = RCD_DEST_STRING;
486           v->c = NULL;
487         }
488     }
489   else 
490     {
491       lex_error (_("expecting output value"));
492       return 0;
493     }
494
495   if ((rcd->flags & RCD_DEST_MASK) == RCD_DEST_ERROR)
496     rcd->flags |= flags;
497 #if 0
498   else if (((rcd->flags & RCD_DEST_MASK) == RCD_DEST_NUMERIC
499             && flags != RCD_DEST_NUMERIC)
500            || ((rcd->flags & RCD_DEST_MASK) == RCD_DEST_STRING
501                && flags != RCD_DEST_STRING))
502 #endif
503     else if ((rcd->flags & RCD_DEST_MASK) ^ flags)
504       {
505         msg (SE, _("Inconsistent output types.  The output values "
506                    "must be all numeric or all string."));
507         return 0;
508       }
509
510   return 1;
511 }
512
513 /* Reads a set of source specifications and returns one of the
514    following values: 0 on failure; 1 for normal success; 2 for success
515    but with CONVERT as the keyword; 3 for success but with ELSE as the
516    keyword. */
517 static int
518 parse_src_spec (struct rcd_var * rcd, int type, size_t max_src_width)
519 {
520   struct coding *c;
521
522   for (;;)
523     {
524       if (rcd->nmap + 1 >= rcd->mmap)
525         {
526           rcd->mmap += 16;
527           rcd->map = xnrealloc (rcd->map, rcd->mmap, sizeof *rcd->map);
528         }
529
530       c = &rcd->map[rcd->nmap];
531       c->f1.c = c->f2.c = NULL;
532       if (lex_match_id ("ELSE"))
533         {
534           c->type = RCD_ELSE;
535           rcd->nmap++;
536           return 3;
537         }
538       else if (type == NUMERIC)
539         {
540           if (token == T_ID)
541             {
542               if (lex_match_id ("LO") || lex_match_id ("LOWEST"))
543                 {
544                   if (!lex_force_match_id ("THRU"))
545                     return 0;
546                   if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
547                     c->type = RCD_ELSE;
548                   else if (lex_is_number ())
549                     {
550                       c->type = RCD_LOW;
551                       c->f1.f = tokval;
552                       lex_get ();
553                     }
554                   else
555                     {
556                       lex_error (_("following LO THRU"));
557                       return 0;
558                     }
559                 }
560               else if (lex_match_id ("MISSING"))
561                 {
562                   c->type = RCD_USER;
563                   rcd->flags |= RCD_MISC_MISSING;
564                 }
565               else if (lex_match_id ("SYSMIS"))
566                 {
567                   c->type = RCD_END;
568                   rcd->flags |= RCD_MISC_MISSING;
569                 }
570               else
571                 {
572                   lex_error (_("in source value"));
573                   return 0;
574                 }
575             }
576           else if (lex_is_number ())
577             {
578               c->f1.f = tokval;
579               lex_get ();
580               if (lex_match_id ("THRU"))
581                 {
582                   if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
583                     c->type = RCD_HIGH;
584                   else if (lex_is_number ())
585                     {
586                       c->type = RCD_RANGE;
587                       c->f2.f = tokval;
588                       lex_get ();
589                     }
590                   else
591                     {
592                       lex_error (NULL);
593                       return 0;
594                     }
595                 }
596               else
597                 c->type = RCD_SINGLE;
598             }
599           else
600             {
601               lex_error (_("in source value"));
602               return 0;
603             }
604         }
605       else
606         {
607           assert (type == ALPHA);
608           if (lex_match_id ("CONVERT"))
609             {
610               if ((rcd->flags & RCD_DEST_MASK) == RCD_DEST_ERROR)
611                 rcd->flags |= RCD_DEST_NUMERIC;
612               else if ((rcd->flags & RCD_DEST_MASK) != RCD_DEST_NUMERIC)
613                 {
614                   msg (SE, _("Keyword CONVERT may only be used with "
615                              "string input values and numeric output "
616                              "values."));
617                   return 0;
618                 }
619
620               c->type = RCD_CONVERT;
621               rcd->nmap++;
622               return 2;
623             }
624           else
625             {
626               /* Only the debugging code needs the NULLs at the ends
627                  of the strings.  However, changing code behavior more
628                  than necessary based on the DEBUGGING `#define' is just
629                  *inviting* bugs. */
630               c->type = RCD_SINGLE;
631               if (!lex_force_string ())
632                 return 0;
633               c->f1.c = xmalloc (max_src_width + 1);
634               str_copy_rpad (c->f1.c, max_src_width + 1, ds_c_str (&tokstr));
635               lex_get ();
636             }
637         }
638
639       if (c->type != RCD_END)
640         rcd->nmap++;
641
642       lex_match (',');
643       if (token == '=')
644         break;
645     }
646   return 1;
647 }
648 \f
649 /* Data transformation. */
650
651 static void
652 recode_trns_free (struct trns_header * t)
653 {
654   size_t i;
655   struct rcd_var *head, *next;
656
657   head = ((struct recode_trns *) t)->codings;
658   while (head)
659     {
660       if (head->map && !(head->flags & RCD_MISC_DUPLICATE))
661         {
662           if (head->flags & RCD_SRC_STRING)
663             for (i = 0; i < head->nmap; i++)
664               switch (head->map[i].type)
665                 {
666                 case RCD_RANGE:
667                   free (head->map[i].f2.c);
668                   /* fall through */
669                 case RCD_USER:
670                 case RCD_SINGLE:
671                 case RCD_HIGH:
672                 case RCD_LOW:
673                   free (head->map[i].f1.c);
674                   break;
675                 case RCD_END:
676                 case RCD_ELSE:
677                 case RCD_CONVERT:
678                   break;
679                 default:
680                   assert (0);
681                 }
682           if (head->flags & RCD_DEST_STRING)
683             for (i = 0; i < head->nmap; i++)
684               if (head->map[i].type != RCD_CONVERT && head->map[i].type != RCD_END)
685                 free (head->map[i].t.c);
686           free (head->map);
687         }
688       next = head->next;
689       free (head);
690       head = next;
691     }
692 }
693
694 static inline struct coding *
695 find_src_numeric (struct rcd_var * v, struct ccase * c)
696 {
697   double cmp = case_num (c, v->src->fv);
698   struct coding *cp;
699
700   if (cmp == SYSMIS)
701     {
702       if (v->sysmis.f != -SYSMIS)
703         {
704           if ((v->flags & RCD_DEST_MASK) == RCD_DEST_NUMERIC)
705             case_data_rw (c, v->dest->fv)->f = v->sysmis.f;
706           else
707             memcpy (case_data_rw (c, v->dest->fv)->s, v->sysmis.s,
708                     v->dest->width);
709         }
710       return NULL;
711     }
712
713   for (cp = v->map;; cp++)
714     switch (cp->type)
715       {
716       case RCD_END:
717         return NULL;
718       case RCD_USER:
719         if (mv_is_num_user_missing (&v->src->miss, cmp))
720           return cp;
721         break;
722       case RCD_SINGLE:
723         if (cmp == cp->f1.f)
724           return cp;
725         break;
726       case RCD_HIGH:
727         if (cmp >= cp->f1.f)
728           return cp;
729         break;
730       case RCD_LOW:
731         if (cmp <= cp->f1.f)
732           return cp;
733         break;
734       case RCD_RANGE:
735         if (cmp >= cp->f1.f && cmp <= cp->f2.f)
736           return cp;
737         break;
738       case RCD_ELSE:
739         return cp;
740       default:
741         assert (0);
742       }
743 }
744
745 static inline struct coding *
746 find_src_string (struct rcd_var * v, struct ccase * c)
747 {
748   const char *cmp = case_str (c, v->src->fv);
749   int w = v->src->width;
750   struct coding *cp;
751
752   for (cp = v->map;; cp++)
753     switch (cp->type)
754       {
755       case RCD_END:
756         return NULL;
757       case RCD_SINGLE:
758         if (!memcmp (cp->f1.c, cmp, w))
759           return cp;
760         break;
761       case RCD_ELSE:
762         return cp;
763       case RCD_CONVERT:
764         {
765           double f = convert_to_double (cmp, w);
766           if (f != -SYSMIS)
767             {
768               case_data_rw (c, v->dest->fv)->f = f;
769               return NULL;
770             }
771           break;
772         }
773       default:
774         assert (0);
775       }
776 }
777
778 static int
779 recode_trns_proc (struct trns_header * t, struct ccase * c,
780                   int case_idx UNUSED)
781 {
782   struct rcd_var *v;
783
784   for (v = ((struct recode_trns *) t)->codings; v; v = v->next)
785     {
786       struct coding *cp;
787
788       switch (v->flags & RCD_SRC_MASK)
789         {
790         case RCD_SRC_NUMERIC:
791           cp = find_src_numeric (v, c);
792           break;
793         case RCD_SRC_STRING:
794           cp = find_src_string (v, c);
795           break;
796         default:
797           assert (0);
798           abort ();
799         }
800       if (!cp)
801         continue;
802
803       /* A matching input value was found. */
804       if ((v->flags & RCD_DEST_MASK) == RCD_DEST_NUMERIC)
805         {
806           double val = cp->t.f;
807           double *out = &case_data_rw (c, v->dest->fv)->f;
808           if (val == -SYSMIS)
809             *out = case_num (c, v->src->fv);
810           else
811             *out = val;
812         }
813       else
814         {
815           char *val = cp->t.c;
816           if (val == NULL) 
817             {
818               if (v->dest->fv != v->src->fv)
819                 buf_copy_rpad (case_data_rw (c, v->dest->fv)->s,
820                                v->dest->width,
821                                case_str (c, v->src->fv), v->src->width); 
822             }
823           else
824             memcpy (case_data_rw (c, v->dest->fv)->s, cp->t.c, v->dest->width);
825         }
826     }
827
828   return -1;
829 }
830
831 /* Convert NPTR to a `long int' in base 10.  Returns the long int on
832    success, NOT_LONG on failure.  On success stores a pointer to the
833    first character after the number into *ENDPTR.  From the GNU C
834    library. */
835 static long int
836 string_to_long (const char *nptr, int width, const char **endptr)
837 {
838   int negative;
839   unsigned long int cutoff;
840   unsigned int cutlim;
841   unsigned long int i;
842   const char *s;
843   unsigned char c;
844   const char *save;
845
846   s = nptr;
847
848   /* Check for a sign.  */
849   if (*s == '-')
850     {
851       negative = 1;
852       ++s;
853     }
854   else if (*s == '+')
855     {
856       negative = 0;
857       ++s;
858     }
859   else
860     negative = 0;
861   if (s >= nptr + width)
862     return NOT_LONG;
863
864   /* Save the pointer so we can check later if anything happened.  */
865   save = s;
866
867   cutoff = ULONG_MAX / 10ul;
868   cutlim = ULONG_MAX % 10ul;
869
870   i = 0;
871   for (c = *s;;)
872     {
873       if (isdigit ((unsigned char) c))
874         c -= '0';
875       else
876         break;
877       /* Check for overflow.  */
878       if (i > cutoff || (i == cutoff && c > cutlim))
879         return NOT_LONG;
880       else
881         i = i * 10ul + c;
882
883       s++;
884       if (s >= nptr + width)
885         break;
886       c = *s;
887     }
888
889   /* Check if anything actually happened.  */
890   if (s == save)
891     return NOT_LONG;
892
893   /* Check for a value that is within the range of `unsigned long
894      int', but outside the range of `long int'.  We limit LONG_MIN and
895      LONG_MAX by one point because we know that NOT_LONG is out there
896      somewhere. */
897   if (i > (negative
898            ? -((unsigned long int) LONG_MIN) - 1
899            : ((unsigned long int) LONG_MAX) - 1))
900     return NOT_LONG;
901
902   *endptr = s;
903
904   /* Return the result of the appropriate sign.  */
905   return (negative ? -i : i);
906 }
907
908 /* Converts S to a double according to format Fx.0.  Returns the value
909    found, or -SYSMIS if there was no valid number in s.  WIDTH is the
910    length of string S.  From the GNU C library. */
911 static double
912 convert_to_double (const char *s, int width)
913 {
914   const char *end = &s[width];
915
916   short int sign;
917
918   /* The number so far.  */
919   double num;
920
921   int got_dot;                  /* Found a decimal point.  */
922   int got_digit;                /* Count of digits.  */
923
924   /* The exponent of the number.  */
925   long int exponent;
926
927   /* Eat whitespace.  */
928   while (s < end && isspace ((unsigned char) *s))
929     ++s;
930   if (s >= end)
931     return SYSMIS;
932
933   /* Get the sign.  */
934   sign = *s == '-' ? -1 : 1;
935   if (*s == '-' || *s == '+')
936     {
937       ++s;
938       if (s >= end)
939         return -SYSMIS;
940     }
941
942   num = 0.0;
943   got_dot = 0;
944   got_digit = 0;
945   exponent = 0;
946   for (; s < end; ++s)
947     {
948       if (isdigit ((unsigned char) *s))
949         {
950           got_digit++;
951
952           /* Make sure that multiplication by 10 will not overflow.  */
953           if (num > DBL_MAX * 0.1)
954             /* The value of the digit doesn't matter, since we have already
955                gotten as many digits as can be represented in a `double'.
956                This doesn't necessarily mean the result will overflow.
957                The exponent may reduce it to within range.
958
959                We just need to record that there was another
960                digit so that we can multiply by 10 later.  */
961             ++exponent;
962           else
963             num = (num * 10.0) + (*s - '0');
964
965           /* Keep track of the number of digits after the decimal point.
966              If we just divided by 10 here, we would lose precision.  */
967           if (got_dot)
968             --exponent;
969         }
970       else if (!got_dot && *s == '.')
971         /* Record that we have found the decimal point.  */
972         got_dot = 1;
973       else
974         break;
975     }
976
977   if (!got_digit)
978     return -SYSMIS;
979
980   if (s < end && (tolower ((unsigned char) (*s)) == 'e'
981                   || tolower ((unsigned char) (*s)) == 'd'))
982     {
983       /* Get the exponent specified after the `e' or `E'.  */
984       long int exp;
985
986       s++;
987       if (s >= end)
988         return -SYSMIS;
989
990       exp = string_to_long (s, end - s, &s);
991       if (exp == NOT_LONG || end == s)
992         return -SYSMIS;
993       exponent += exp;
994     }
995
996   while (s < end && isspace ((unsigned char) *s))
997     s++;
998   if (s < end)
999     return -SYSMIS;
1000
1001   if (num == 0.0)
1002     return 0.0;
1003
1004   /* Multiply NUM by 10 to the EXPONENT power,
1005      checking for overflow and underflow.  */
1006
1007   if (exponent < 0)
1008     {
1009       if (-exponent + got_digit > -(DBL_MIN_10_EXP) + 5
1010           || num < DBL_MIN * pow (10.0, (double) -exponent))
1011         return -SYSMIS;
1012       num *= pow (10.0, (double) exponent);
1013     }
1014   else if (exponent > 0)
1015     {
1016       if (num > DBL_MAX * pow (10.0, (double) -exponent))
1017         return -SYSMIS;
1018       num *= pow (10.0, (double) exponent);
1019     }
1020
1021   return sign > 0 ? num : -num;
1022 }