- /* Whether we've already encountered a specification for SYSMIS. */
- int had_sysmis = 0;
-
- /* Initialize this rcd_var to ensure proper cleanup. */
- rcd->next = NULL;
- rcd->map = NULL;
- rcd->nmap = rcd->mmap = 0;
- rcd->has_sysmis = 0;
- rcd->sysmis.f = 0;
-
- /* Parse variable names. */
- if (!parse_variables (default_dict, &v, &nv, PV_SAME_TYPE))
- goto lossage;
-
- /* Ensure all variables are same type; find length of longest
- source variable. */
- type = v[0]->type;
- max_src_width = v[0]->width;
-
- if (type == ALPHA)
- for (i = 0; i < nv; i++)
- if (v[i]->width > (int) max_src_width)
- max_src_width = v[i]->width;
-
- /* Set up flags. */
- rcd->flags = 0;
- if (type == NUMERIC)
- rcd->flags |= RCD_SRC_NUMERIC;
- else
- rcd->flags |= RCD_SRC_STRING;
-
- /* Parse each coding in parentheses. */
- max_dst_width = 0;
- if (!lex_force_match ('('))
- goto lossage;
- for (;;)
- {
- /* Get the input value (before the `='). */
- int mark = rcd->nmap;
- int code = parse_src_spec (rcd, type, max_src_width);
- if (!code)
- goto lossage;
-
- /* ELSE is the same as any other input spec except that it
- precludes later sysmis specifications. */
- if (code == 3)
- {
- had_sysmis = 1;
- code = 1;
- }
-
- /* If keyword CONVERT was specified, there is no output
- specification. */
- if (code == 1)
- {
- union value output;
-
- /* Get the output value (after the `='). */
- lex_get (); /* Skip `='. */
- if (!parse_dest_spec (rcd, &output, &max_dst_width))
- goto lossage;
-
- /* Set the value for SYSMIS if requested and if we don't
- already have one. */
- if ((rcd->flags & RCD_MISC_MISSING) && !had_sysmis)
- {
- rcd->has_sysmis = 1;
- if ((rcd->flags & RCD_DEST_MASK) == RCD_DEST_NUMERIC)
- rcd->sysmis.f = output.f;
- else
- rcd->sysmis.c = xstrdup (output.c);
- had_sysmis = 1;
-
- rcd->flags &= ~RCD_MISC_MISSING;
- }
-
- /* Since there may be multiple input values for a single
- output, the output value need to propagated among all
- of them. */
- if ((rcd->flags & RCD_DEST_MASK) == RCD_DEST_NUMERIC)
- for (i = mark; i < rcd->nmap; i++)
- rcd->map[i].t.f = output.f;
- else
- {
- for (i = mark; i < rcd->nmap; i++)
- rcd->map[i].t.c = xstrdup (output.c);
- free (output.c);
- }
- }
- lex_get (); /* Skip `)'. */
- if (!lex_match ('('))
- break;
- }
-
- /* Append sentinel value. */
- rcd->map[rcd->nmap++].type = RCD_END;
-
- /* Since multiple variables may use the same recodings, it is
- necessary to propogate the codings to all of them. */
- rcd->src = v[0];
- rcd->dest = v[0];
- rcd->dest_name[0] = 0;
- iter = rcd;
- for (i = 1; i < nv; i++)
- {
- iter = iter->next = xmalloc (sizeof *iter);
- iter->next = NULL;
- iter->flags = rcd->flags | RCD_MISC_DUPLICATE;
- iter->src = v[i];
- iter->dest = v[i];
- iter->dest_name[0] = 0;
- iter->has_sysmis = rcd->has_sysmis;
- iter->sysmis = rcd->sysmis;
- iter->map = rcd->map;
- }
-
- if (lex_match_id ("INTO"))
- {
- char **names;
- int nnames;
-
- int success = 0;
-
- if (!parse_mixed_vars (&names, &nnames, PV_NONE))
- goto lossage;
-
- if (nnames != nv)
- {
- for (i = 0; i < nnames; i++)
- free (names[i]);
- free (names);
- msg (SE, _("%d variable(s) cannot be recoded into "
- "%d variable(s). Specify the same number "
- "of variables as input and output variables."),
- nv, nnames);
- goto lossage;
- }
-
- if ((rcd->flags & RCD_DEST_MASK) == RCD_DEST_STRING)
- for (i = 0, iter = rcd; i < nv; i++, iter = iter->next)
- {
- struct variable *v = dict_lookup_var (default_dict, names[i]);
-
- if (!v)
- {
- msg (SE, _("There is no string variable named "
- "%s. (All string variables specified "
- "on INTO must already exist. Use the "
- "STRING command to create a string "
- "variable.)"), names[i]);
- goto INTO_fail;
- }
- if (v->type != ALPHA)
- {
- msg (SE, _("Type mismatch between input and output "
- "variables. Output variable %s is not "
- "a string variable, but all the input "
- "variables are string variables."), v->name);
- goto INTO_fail;
- }
- if (v->width > (int) max_dst_width)
- max_dst_width = v->width;
- iter->dest = v;
- }
- else
- for (i = 0, iter = rcd; i < nv; i++, iter = iter->next)
- {
- struct variable *v = dict_lookup_var (default_dict, names[i]);
-
- if (v)
- {
- if (v->type != NUMERIC)
- {
- msg (SE, _("Type mismatch after INTO: %s "
- "is not a numeric variable."), v->name);
- goto INTO_fail;
- }
- else
- iter->dest = v;
- }
- else
- strcpy (iter->dest_name, names[i]);
- }
- success = 1;
-
- /* Note that regardless of whether we succeed or fail,
- flow-of-control comes here. `success' is the important
- factor. Ah, if C had garbage collection... */
- INTO_fail:
- for (i = 0; i < nnames; i++)
- free (names[i]);
- free (names);
- if (!success)
- goto lossage;
- }
- else
- {
- if (max_src_width > max_dst_width)
- max_dst_width = max_src_width;
-
- if ((rcd->flags & RCD_SRC_MASK) == RCD_SRC_NUMERIC
- && (rcd->flags & RCD_DEST_MASK) != RCD_DEST_NUMERIC)
- {
- msg (SE, _("INTO must be used when the input values are "
- "numeric and output values are string."));
- goto lossage;
- }
-
- if ((rcd->flags & RCD_SRC_MASK) != RCD_SRC_NUMERIC
- && (rcd->flags & RCD_DEST_MASK) == RCD_DEST_NUMERIC)
- {
- msg (SE, _("INTO must be used when the input values are "
- "string and output values are numeric."));
- goto lossage;
- }
- }
-
- if ((rcd->flags & RCD_DEST_MASK) == RCD_DEST_STRING)
- {
- struct coding *cp;
-
- for (cp = rcd->map; cp->type != RCD_END; cp++)
- if (cp->t.c)
- {
- if (strlen (cp->t.c) < max_dst_width)
- {
- /* The NULL is only really necessary for the
- debugging code. */
- char *repl = xmalloc (max_dst_width + 1);
- st_pad_copy (repl, cp->t.c, max_dst_width + 1);
- free (cp->t.c);
- cp->t.c = repl;
- }
- else
- /* The strings are guaranteed to be in order of
- nondecreasing length. */
- break;
- }
-
- }
-
- if (!lex_match ('/'))
- break;
- while (rcd->next)
- rcd = rcd->next;
- rcd = rcd->next = xmalloc (sizeof *rcd);
-
- free (v);
- v = NULL;