Exemple #1
0
static void
run_old_and_new_dialog (struct recode_dialog *rd)
{
  gint response;
  GtkListStore *local_store = clone_list_store (rd->value_map);

  psppire_acr_set_model (rd->acr, local_store);
  psppire_acr_set_get_value_func (rd->acr, set_value, rd);

  gtk_window_set_title (GTK_WINDOW (rd->old_and_new_dialog),
			rd->different
			? _("Recode into Different Variables: Old and New Values ")
			: _("Recode into Same Variables: Old and New Values")
			);


  {
    /* Find the type of the first variable (it's invariant that
       all variables are of the same type) */
    const struct variable *v;
    GtkTreeIter iter;
    GtkTreeModel *model =
      gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview));

    gboolean not_empty = gtk_tree_model_get_iter_first (model, &iter);

    g_return_if_fail (not_empty);

    gtk_tree_model_get (model, &iter, 0, &v, -1);

    rd->input_var_is_string = var_is_alpha (v);

    g_object_set (rd->old_value_chooser, "is-string", rd->input_var_is_string, NULL);

    gtk_widget_set_sensitive (rd->toggle [BUTTON_NEW_SYSMIS],
			      var_is_numeric (v));

    gtk_widget_set_sensitive (rd->convert_button, var_is_alpha (v));
  }


  response = psppire_dialog_run (rd->old_and_new_dialog);
  psppire_acr_set_model (rd->acr, NULL);


  if ( response == PSPPIRE_RESPONSE_CONTINUE )
    {
      g_object_unref (rd->value_map);
      rd->value_map = clone_list_store (local_store);
    }
  else
    g_object_unref (local_store);


  psppire_dialog_notify_change (PSPPIRE_DIALOG (rd->dialog));
}
Exemple #2
0
/* Formats a value according to VAR's print format and strips white space
   appropriately for VAR's type.  That is, if VAR is numeric, strips leading
   white space (because numbers are right-justified within their fields), and
   if VAR is string, strips trailing white space (because spaces pad out string
   values on the right).

   Returns an allocated string.  The returned string must be freed when no
   longer required. */
gchar *
value_to_text (union value v, const struct variable *var)
{
  gchar *s;

  s = data_out (&v, var_get_encoding (var), var_get_print_format (var));
  if (var_is_numeric (var))
    g_strchug (s);
  else
    g_strchomp (s);

  return s;
}
static void
run_define_groups (PsppireDialogActionIndepSamps *act)
{
  gint response;
  PsppireDialogAction *da = PSPPIRE_DIALOG_ACTION (act);

  if ( act->dg_table2->parent)
    gtk_container_remove (GTK_CONTAINER (act->dg_table2->parent), act->dg_table2);

  if ( act->dg_table1->parent)
    gtk_container_remove (GTK_CONTAINER (act->dg_table1->parent), act->dg_table1);


  if ( var_is_numeric (act->grp_var))
    {
      gtk_table_attach_defaults (GTK_TABLE (act->dg_table1), act->dg_table2,
  				 1, 2, 1, 2);

      gtk_container_add (GTK_CONTAINER (act->dg_box), act->dg_table1);
    }
  else
    {
      gtk_container_add (GTK_CONTAINER (act->dg_box), act->dg_table2);
      act->group_defn = GROUPS_VALUES;
    }


  psppire_dialog_set_valid_predicate (PSPPIRE_DIALOG (act->dg_dialog),
  				      define_groups_state_valid, act);

  psppire_value_entry_set_variable (PSPPIRE_VALUE_ENTRY (act->dg_grp_entry[0]), act->grp_var);
  psppire_value_entry_set_variable (PSPPIRE_VALUE_ENTRY (act->dg_grp_entry[1]), act->grp_var);
  psppire_value_entry_set_variable (PSPPIRE_VALUE_ENTRY (act->dg_cut_point_entry), act->grp_var);

  if ( act->group_defn != GROUPS_CUT_POINT )
    {
      gtk_toggle_button_set_active
  	(GTK_TOGGLE_BUTTON (act->dg_cut_point_toggle_button), TRUE);

      gtk_toggle_button_set_active
  	(GTK_TOGGLE_BUTTON (act->dg_values_toggle_button), TRUE);
    }
  else
    {
      gtk_toggle_button_set_active
  	(GTK_TOGGLE_BUTTON (act->dg_values_toggle_button), TRUE);

      gtk_toggle_button_set_active
  	(GTK_TOGGLE_BUTTON (act->dg_cut_point_toggle_button), TRUE);
    }

  g_signal_emit_by_name (act->dg_grp_entry[0], "changed");
  g_signal_emit_by_name (act->dg_grp_entry[1], "changed");
  g_signal_emit_by_name (act->dg_cut_point_entry, "changed");

  response = psppire_dialog_run (PSPPIRE_DIALOG (act->def_grps_dialog));

  if (response == PSPPIRE_RESPONSE_CONTINUE)
    {
      const int width = var_get_width (act->grp_var);

      if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->dg_values_toggle_button)))
	{
	  act->group_defn = GROUPS_VALUES;

          psppire_value_entry_get_value (PSPPIRE_VALUE_ENTRY (act->dg_grp_entry[0]),
					 &act->grp_val[0], width);

          psppire_value_entry_get_value (PSPPIRE_VALUE_ENTRY (act->dg_grp_entry[1]),
					 &act->grp_val[1], width);
	}
      else
	{
	  act->group_defn = GROUPS_CUT_POINT;

          psppire_value_entry_get_value (PSPPIRE_VALUE_ENTRY (act->dg_cut_point_entry),
					 &act->cut_point, width);
	}

      psppire_dialog_notify_change (PSPPIRE_DIALOG (da->dialog));
    }
}
Exemple #4
0
int
cmd_missing_values (struct lexer *lexer, struct dataset *ds)
{
  struct dictionary *dict = dataset_dict (ds);
  struct variable **v = NULL;
  size_t nv;

  bool ok = true;

  while (lex_token (lexer) != T_ENDCMD)
    {
      size_t i;

      if (!parse_variables (lexer, dict, &v, &nv, PV_NONE))
        goto error;

      if (!lex_force_match (lexer, T_LPAREN))
        goto error;

      for (i = 0; i < nv; i++)
        var_clear_missing_values (v[i]);

      if (!lex_match (lexer, T_RPAREN))
        {
          struct missing_values mv;

          for (i = 0; i < nv; i++)
            if (var_get_type (v[i]) != var_get_type (v[0]))
              {
                const struct variable *n = var_is_numeric (v[0]) ? v[0] : v[i];
                const struct variable *s = var_is_numeric (v[0]) ? v[i] : v[0];
                msg (SE, _("Cannot mix numeric variables (e.g. %s) and "
                           "string variables (e.g. %s) within a single list."),
                     var_get_name (n), var_get_name (s));
                goto error;
              }

          if (var_is_numeric (v[0]))
            {
              mv_init (&mv, 0);
              while (!lex_match (lexer, T_RPAREN))
                {
                  enum fmt_type type = var_get_print_format (v[0])->type;
                  double x, y;
                  bool ok;

                  if (!parse_num_range (lexer, &x, &y, &type))
                    goto error;

                  ok = (x == y
                        ? mv_add_num (&mv, x)
                        : mv_add_range (&mv, x, y));
                  if (!ok)
                    ok = false;

                  lex_match (lexer, T_COMMA);
                }
            }
          else
            {
              mv_init (&mv, MV_MAX_STRING);
              while (!lex_match (lexer, T_RPAREN))
                {
                  uint8_t value[MV_MAX_STRING];
                  char *dict_mv;
                  size_t length;

                  if (!lex_force_string (lexer))
                    {
                      ok = false;
                      break;
                    }

                  dict_mv = recode_string (dict_get_encoding (dict), "UTF-8",
                                           lex_tokcstr (lexer),
                                           ss_length (lex_tokss (lexer)));
                  length = strlen (dict_mv);
                  if (length > MV_MAX_STRING)
                    {
                      /* XXX truncate graphemes not bytes */
                      msg (SE, _("Truncating missing value to maximum "
                                 "acceptable length (%d bytes)."),
                           MV_MAX_STRING);
                      length = MV_MAX_STRING;
                    }
                  memset (value, ' ', MV_MAX_STRING);
                  memcpy (value, dict_mv, length);
                  free (dict_mv);

                  if (!mv_add_str (&mv, value))
                    ok = false;

                  lex_get (lexer);
                  lex_match (lexer, T_COMMA);
                }
            }

          for (i = 0; i < nv; i++)
            {
              if (mv_is_resizable (&mv, var_get_width (v[i])))
                var_set_missing_values (v[i], &mv);
              else
                {
                  msg (SE, _("Missing values provided are too long to assign "
                             "to variable of width %d."),
                       var_get_width (v[i]));
                  ok = false;
                }
            }

          mv_destroy (&mv);
        }

      lex_match (lexer, T_SLASH);
      free (v);
      v = NULL;
    }

  free (v);
  return ok ? CMD_SUCCESS : CMD_FAILURE;

error:
  free (v);
  return CMD_FAILURE;
}
Exemple #5
0
static void
reset_type_label_dialog (struct compute_dialog *cd)
{
  const gchar *target_name;
  struct variable *target_var;

  GtkWidget *width_entry =
    get_widget_assert (cd->xml, "type-and-label-width");

  GtkWidget *label_entry =
    get_widget_assert (cd->xml, "type-and-label-label-entry");

  GtkWidget *numeric_target =
    get_widget_assert (cd->xml, "radio-button-numeric");

  GtkWidget *string_target =
    get_widget_assert (cd->xml, "radio-button-string");


  target_name = gtk_entry_get_text
    (GTK_ENTRY (get_widget_assert (cd->xml, "compute-entry1")));


  if ( (target_var = psppire_dict_lookup_var (cd->dict, target_name)) )
    {
      /* Existing Variable */
      const gchar *label ;
      GtkWidget *user_label =
	get_widget_assert (cd->xml, "radio-button-user-label");

      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (user_label), TRUE);

      label = var_get_label (target_var);

      if ( label )
	{
	  gtk_entry_set_text (GTK_ENTRY (label_entry), label);
	}

      gtk_widget_set_sensitive (width_entry, FALSE);

      if ( var_is_numeric (target_var))
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (numeric_target),
				      TRUE);
      else
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (string_target),
				      TRUE);

      gtk_widget_set_sensitive (numeric_target, FALSE);
      gtk_widget_set_sensitive (string_target, FALSE);
    }
  else
    {
      GtkWidget *expression =
	get_widget_assert (cd->xml, "radio-button-expression-label");

      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (expression), TRUE);

      gtk_widget_set_sensitive (width_entry, TRUE);
      gtk_widget_set_sensitive (numeric_target, TRUE);
      gtk_widget_set_sensitive (string_target, TRUE);

      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (numeric_target),
				    TRUE);
    }

}
Exemple #6
0
/* Shows the dialog box and sets default values */
void
missing_val_dialog_show (struct missing_val_dialog *dialog)
{
  gint i;
  g_return_if_fail (dialog);
  g_return_if_fail (dialog->pv);

  mv_copy (&dialog->mvl, var_get_missing_values (dialog->pv));

  /* Blank all entry boxes and make them insensitive */
  gtk_entry_set_text (GTK_ENTRY (dialog->low), "");
  gtk_entry_set_text (GTK_ENTRY (dialog->high), "");
  gtk_entry_set_text (GTK_ENTRY (dialog->discrete), "");
  gtk_widget_set_sensitive (dialog->low, FALSE);
  gtk_widget_set_sensitive (dialog->high, FALSE);
  gtk_widget_set_sensitive (dialog->discrete, FALSE);

  gtk_widget_set_sensitive (GTK_WIDGET (dialog->button_range),
			   var_is_numeric (dialog->pv));


  for (i = 0 ; i < 3 ; ++i )
    {
      gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), "");
      gtk_widget_set_sensitive (dialog->mv[i], FALSE);
    }

  if ( mv_has_range (&dialog->mvl))
    {
      union value low, high;
      gchar *low_text;
      gchar *high_text;
      mv_get_range (&dialog->mvl, &low.f, &high.f);


      low_text = value_to_text (low, dialog->pv);
      high_text = value_to_text (high, dialog->pv);

      gtk_entry_set_text (GTK_ENTRY (dialog->low), low_text);
      gtk_entry_set_text (GTK_ENTRY (dialog->high), high_text);
      g_free (low_text);
      g_free (high_text);

      if ( mv_has_value (&dialog->mvl))
	{
	  gchar *text;
	  text = value_to_text (*mv_get_value (&dialog->mvl, 0), dialog->pv);
	  gtk_entry_set_text (GTK_ENTRY (dialog->discrete), text);
	  g_free (text);
	}

      gtk_toggle_button_set_active (dialog->button_range, TRUE);
      gtk_widget_set_sensitive (dialog->low, TRUE);
      gtk_widget_set_sensitive (dialog->high, TRUE);
      gtk_widget_set_sensitive (dialog->discrete, TRUE);

    }
  else if ( mv_has_value (&dialog->mvl))
    {
      const int n = mv_n_values (&dialog->mvl);

      for (i = 0 ; i < 3 ; ++i )
	{
	  if ( i < n)
	    {
	      gchar *text ;

	      text = value_to_text (*mv_get_value (&dialog->mvl, i), dialog->pv);
	      gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), text);
	      g_free (text);
	    }
	  gtk_widget_set_sensitive (dialog->mv[i], TRUE);
	}
      gtk_toggle_button_set_active (dialog->button_discrete, TRUE);
    }
  else if ( mv_is_empty (&dialog->mvl))
    {
      gtk_toggle_button_set_active (dialog->button_none, TRUE);
    }

  gtk_widget_show (dialog->window);
}
static void
run_define_groups (struct tt_indep_samples_dialog *ttd)
{
  struct tt_groups_dialog *grps = ttd->grps;

  gint response;

  GtkWidget *box = get_widget_assert (ttd->xml, "dialog-hbox2");

  const gchar *text = gtk_entry_get_text (GTK_ENTRY (ttd->groups_entry));

  const struct variable *v = psppire_dict_lookup_var (ttd->dict, text);

  if ( grps->table2->parent)
    gtk_container_remove (GTK_CONTAINER (grps->table2->parent), grps->table2);

  if ( grps->table1->parent)
    gtk_container_remove (GTK_CONTAINER (grps->table1->parent), grps->table1);


  if ( var_is_numeric (v))
    {
      gtk_table_attach_defaults (GTK_TABLE (grps->table1), grps->table2,
				 1, 2, 1, 2);

      gtk_container_add (GTK_CONTAINER (box), grps->table1);
    }
  else
    {
      gtk_container_add (GTK_CONTAINER (box), grps->table2);
      grps->group_defn = GROUPS_VALUES;
    }


  psppire_dialog_set_valid_predicate (PSPPIRE_DIALOG (grps->dialog),
				      define_groups_state_valid, grps);

  if ( grps->group_defn != GROUPS_CUT_POINT )
    {
      gtk_toggle_button_set_active
	(GTK_TOGGLE_BUTTON (grps->cut_point_toggle_button), TRUE);

      gtk_toggle_button_set_active
	(GTK_TOGGLE_BUTTON (grps->values_toggle_button), TRUE);

      gtk_entry_set_text (GTK_ENTRY (grps->grp_entry[0]), grps->val[0]);
      gtk_entry_set_text (GTK_ENTRY (grps->grp_entry[1]), grps->val[1]);

      gtk_entry_set_text (GTK_ENTRY (grps->cut_point_entry), "");
    }
  else
    {
      gtk_toggle_button_set_active
	(GTK_TOGGLE_BUTTON (grps->values_toggle_button), TRUE);

      gtk_toggle_button_set_active
	(GTK_TOGGLE_BUTTON (grps->cut_point_toggle_button), TRUE);

      gtk_entry_set_text (GTK_ENTRY (grps->grp_entry[0]), "");
      gtk_entry_set_text (GTK_ENTRY (grps->grp_entry[1]), "");

      gtk_entry_set_text (GTK_ENTRY (grps->cut_point_entry), grps->val[0]);
    }

  g_signal_emit_by_name (grps->grp_entry[0], "changed");
  g_signal_emit_by_name (grps->grp_entry[1], "changed");
  g_signal_emit_by_name (grps->cut_point_entry, "changed");

  response = psppire_dialog_run (PSPPIRE_DIALOG (grps->dialog));

  if (response == PSPPIRE_RESPONSE_CONTINUE)
    {
      g_free (grps->val[0]);
      g_free (grps->val[1]);

      if (gtk_toggle_button_get_active
	  (GTK_TOGGLE_BUTTON (grps->values_toggle_button)))
	{
	  grps->group_defn = GROUPS_VALUES;

	  grps->val[0] =
	    xstrdup (gtk_entry_get_text (GTK_ENTRY (grps->grp_entry[0])));

	  grps->val[1] =
	    xstrdup (gtk_entry_get_text (GTK_ENTRY (grps->grp_entry[1])));
	}
      else
	{
	  grps->group_defn = GROUPS_CUT_POINT;

	  grps->val[1] = NULL;

	  grps->val[0] =
	    xstrdup (gtk_entry_get_text (GTK_ENTRY (grps->cut_point_entry)));
	}

      psppire_dialog_notify_change (PSPPIRE_DIALOG (ttd->dialog));
    }
}
Exemple #8
0
/* Merge the dictionary for file F into master dictionary M. */
static bool
merge_dictionary (struct dictionary *const m, struct comb_file *f)
{
  struct dictionary *d = f->dict;
  const struct string_array *d_docs, *m_docs;
  int i;

  if (dict_get_label (m) == NULL)
    dict_set_label (m, dict_get_label (d));

  d_docs = dict_get_documents (d);
  m_docs = dict_get_documents (m);


  /* FIXME: If the input files have different encodings, then
     the result is undefined.
     The correct thing to do would be to convert to an encoding
     which can cope with all the input files (eg UTF-8).
   */
  if ( 0 != strcmp (dict_get_encoding (f->dict), dict_get_encoding (m)))
    msg (MW, _("Combining files with incompatible encodings. String data may "
               "not be represented correctly."));

  if (d_docs != NULL)
    {
      if (m_docs == NULL)
        dict_set_documents (m, d_docs);
      else
        {
          struct string_array new_docs;
          size_t i;

          new_docs.n = m_docs->n + d_docs->n;
          new_docs.strings = xmalloc (new_docs.n * sizeof *new_docs.strings);
          for (i = 0; i < m_docs->n; i++)
            new_docs.strings[i] = m_docs->strings[i];
          for (i = 0; i < d_docs->n; i++)
            new_docs.strings[m_docs->n + i] = d_docs->strings[i];

          dict_set_documents (m, &new_docs);

          free (new_docs.strings);
        }
    }

  for (i = 0; i < dict_get_var_cnt (d); i++)
    {
      struct variable *dv = dict_get_var (d, i);
      struct variable *mv = dict_lookup_var (m, var_get_name (dv));

      if (dict_class_from_id (var_get_name (dv)) == DC_SCRATCH)
        continue;

      if (mv != NULL)
        {
          if (var_get_width (mv) != var_get_width (dv))
            {
              const char *var_name = var_get_name (dv);
              struct string s = DS_EMPTY_INITIALIZER;
              const char *file_name;

              file_name = f->handle ? fh_get_name (f->handle) : "*";
              ds_put_format (&s,
                             _("Variable %s in file %s has different "
                               "type or width from the same variable in "
                               "earlier file."),
                             var_name, file_name);
              ds_put_cstr (&s, "  ");
              if (var_is_numeric (dv))
                ds_put_format (&s, _("In file %s, %s is numeric."),
                               file_name, var_name);
              else
                ds_put_format (&s, _("In file %s, %s is a string variable "
                                     "with width %d."),
                               file_name, var_name, var_get_width (dv));
              ds_put_cstr (&s, "  ");
              if (var_is_numeric (mv))
                ds_put_format (&s, _("In an earlier file, %s was numeric."),
                               var_name);
              else
                ds_put_format (&s, _("In an earlier file, %s was a string "
                                     "variable with width %d."),
                               var_name, var_get_width (mv));
              msg (SE, "%s", ds_cstr (&s));
              ds_destroy (&s);
              return false;
            }

          if (var_has_value_labels (dv) && !var_has_value_labels (mv))
            var_set_value_labels (mv, var_get_value_labels (dv));
          if (var_has_missing_values (dv) && !var_has_missing_values (mv))
            var_set_missing_values (mv, var_get_missing_values (dv));
          if (var_get_label (dv) && !var_get_label (mv))
            var_set_label (mv, var_get_label (dv));
        }
      else
        mv = dict_clone_var_assert (m, dv);
    }

  return true;
}
Exemple #9
0
/* Parse all the aggregate functions. */
static bool
parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict,
			   struct agr_proc *agr)
{
  struct agr_var *tail; /* Tail of linked list starting at agr->vars. */

  /* Parse everything. */
  tail = NULL;
  for (;;)
    {
      char **dest;
      char **dest_label;
      size_t n_dest;
      struct string function_name;

      enum mv_class exclude;
      const struct agr_func *function;
      int func_index;

      union agr_argument arg[2];

      const struct variable **src;
      size_t n_src;

      size_t i;

      dest = NULL;
      dest_label = NULL;
      n_dest = 0;
      src = NULL;
      function = NULL;
      n_src = 0;
      arg[0].c = NULL;
      arg[1].c = NULL;
      ds_init_empty (&function_name);

      /* Parse the list of target variables. */
      while (!lex_match (lexer, T_EQUALS))
	{
	  size_t n_dest_prev = n_dest;

	  if (!parse_DATA_LIST_vars (lexer, dict, &dest, &n_dest,
                                     (PV_APPEND | PV_SINGLE | PV_NO_SCRATCH
                                      | PV_NO_DUPLICATE)))
	    goto error;

	  /* Assign empty labels. */
	  {
	    int j;

	    dest_label = xnrealloc (dest_label, n_dest, sizeof *dest_label);
	    for (j = n_dest_prev; j < n_dest; j++)
	      dest_label[j] = NULL;
	  }



	  if (lex_is_string (lexer))
	    {
	      dest_label[n_dest - 1] = xstrdup (lex_tokcstr (lexer));
	      lex_get (lexer);
	    }
	}

      /* Get the name of the aggregation function. */
      if (lex_token (lexer) != T_ID)
	{
	  lex_error (lexer, _("expecting aggregation function"));
	  goto error;
	}

      ds_assign_substring (&function_name, lex_tokss (lexer));
      exclude = ds_chomp_byte (&function_name, '.') ? MV_SYSTEM : MV_ANY;

      for (function = agr_func_tab; function->name; function++)
	if (!c_strcasecmp (function->name, ds_cstr (&function_name)))
	  break;
      if (NULL == function->name)
	{
	  msg (SE, _("Unknown aggregation function %s."),
	       ds_cstr (&function_name));
	  goto error;
	}
      ds_destroy (&function_name);
      func_index = function - agr_func_tab;
      lex_get (lexer);

      /* Check for leading lparen. */
      if (!lex_match (lexer, T_LPAREN))
	{
	  if (function->src_vars == AGR_SV_YES)
	    {
              lex_force_match (lexer, T_LPAREN);
	      goto error;
	    }
	}
      else
        {
	  /* Parse list of source variables. */
	  {
	    int pv_opts = PV_NO_SCRATCH;

	    if (func_index == SUM || func_index == MEAN || func_index == SD)
	      pv_opts |= PV_NUMERIC;
	    else if (function->n_args)
	      pv_opts |= PV_SAME_TYPE;

	    if (!parse_variables_const (lexer, dict, &src, &n_src, pv_opts))
	      goto error;
	  }

	  /* Parse function arguments, for those functions that
	     require arguments. */
	  if (function->n_args != 0)
	    for (i = 0; i < function->n_args; i++)
	      {
		int type;

		lex_match (lexer, T_COMMA);
		if (lex_is_string (lexer))
		  {
		    arg[i].c = recode_string (dict_get_encoding (agr->dict),
                                              "UTF-8", lex_tokcstr (lexer),
                                              -1);
		    type = VAL_STRING;
		  }
		else if (lex_is_number (lexer))
		  {
		    arg[i].f = lex_tokval (lexer);
		    type = VAL_NUMERIC;
		  }
                else
                  {
		    msg (SE, _("Missing argument %zu to %s."),
                         i + 1, function->name);
		    goto error;
		  }

		lex_get (lexer);

		if (type != var_get_type (src[0]))
		  {
		    msg (SE, _("Arguments to %s must be of same type as "
			       "source variables."),
			 function->name);
		    goto error;
		  }
	      }

	  /* Trailing rparen. */
	  if (!lex_force_match (lexer, T_RPAREN))
            goto error;

	  /* Now check that the number of source variables match
	     the number of target variables.  If we check earlier
	     than this, the user can get very misleading error
	     message, i.e. `AGGREGATE x=SUM(y t).' will get this
	     error message when a proper message would be more
	     like `unknown variable t'. */
	  if (n_src != n_dest)
	    {
	      msg (SE, _("Number of source variables (%zu) does not match "
			 "number of target variables (%zu)."),
		    n_src, n_dest);
	      goto error;
	    }

          if ((func_index == PIN || func_index == POUT
              || func_index == FIN || func_index == FOUT)
              && (var_is_numeric (src[0])
                  ? arg[0].f > arg[1].f
                  : str_compare_rpad (arg[0].c, arg[1].c) > 0))
            {
              union agr_argument t = arg[0];
              arg[0] = arg[1];
              arg[1] = t;

              msg (SW, _("The value arguments passed to the %s function "
                         "are out-of-order.  They will be treated as if "
                         "they had been specified in the correct order."),
                   function->name);
            }
	}

      /* Finally add these to the linked list of aggregation
         variables. */
      for (i = 0; i < n_dest; i++)
	{
	  struct agr_var *v = xzalloc (sizeof *v);

	  /* Add variable to chain. */
	  if (agr->agr_vars != NULL)
	    tail->next = v;
	  else
	    agr->agr_vars = v;
          tail = v;
	  tail->next = NULL;
          v->moments = NULL;

	  /* Create the target variable in the aggregate
             dictionary. */
	  {
	    struct variable *destvar;

	    v->function = func_index;

	    if (src)
	      {
		v->src = src[i];

		if (var_is_alpha (src[i]))
		  {
		    v->function |= FSTRING;
		    v->string = xmalloc (var_get_width (src[i]));
		  }

		if (function->alpha_type == VAL_STRING)
		  destvar = dict_clone_var_as (agr->dict, v->src, dest[i]);
		else
                  {
                    assert (var_is_numeric (v->src)
                            || function->alpha_type == VAL_NUMERIC);
                    destvar = dict_create_var (agr->dict, dest[i], 0);
                    if (destvar != NULL)
                      {
                        struct fmt_spec f;
                        if ((func_index == N || func_index == NMISS)
                            && dict_get_weight (dict) != NULL)
                          f = fmt_for_output (FMT_F, 8, 2);
                        else
                          f = function->format;
                        var_set_both_formats (destvar, &f);
                      }
                  }
	      } else {
                struct fmt_spec f;
		v->src = NULL;
		destvar = dict_create_var (agr->dict, dest[i], 0);
		if (destvar != NULL)
		  {
		    if ((func_index == N || func_index == NMISS)
			&& dict_get_weight (dict) != NULL)
		      f = fmt_for_output (FMT_F, 8, 2);
		    else
		      f = function->format;
		    var_set_both_formats (destvar, &f);
		  }
	    }

	    if (!destvar)
	      {
		msg (SE, _("Variable name %s is not unique within the "
			   "aggregate file dictionary, which contains "
			   "the aggregate variables and the break "
			   "variables."),
		     dest[i]);
		goto error;
	      }

	    free (dest[i]);
	    if (dest_label[i])
              var_set_label (destvar, dest_label[i]);

	    v->dest = destvar;
	  }

	  v->exclude = exclude;

	  if (v->src != NULL)
	    {
	      int j;

	      if (var_is_numeric (v->src))
		for (j = 0; j < function->n_args; j++)
		  v->arg[j].f = arg[j].f;
	      else
		for (j = 0; j < function->n_args; j++)
		  v->arg[j].c = xstrdup (arg[j].c);
	    }
	}

      if (src != NULL && var_is_alpha (src[0]))
	for (i = 0; i < function->n_args; i++)
	  {
	    free (arg[i].c);
	    arg[i].c = NULL;
	  }

      free (src);
      free (dest);
      free (dest_label);

      if (!lex_match (lexer, T_SLASH))
	{
	  if (lex_token (lexer) == T_ENDCMD)
	    return true;

	  lex_error (lexer, "expecting end of command");
	  return false;
	}
      continue;

    error:
      ds_destroy (&function_name);
      for (i = 0; i < n_dest; i++)
	{
	  free (dest[i]);
	  free (dest_label[i]);
	}
      free (dest);
      free (dest_label);
      free (arg[0].c);
      free (arg[1].c);
      if (src && n_src && var_is_alpha (src[0]))
	for (i = 0; i < function->n_args; i++)
	  {
	    free (arg[i].c);
	    arg[i].c = NULL;
	  }
      free (src);

      return false;
    }
}