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