/* Callback which occurs when the OK button is clicked */ static void missing_val_dialog_accept (GtkWidget *w, gpointer data) { struct missing_val_dialog *dialog = data; if ( gtk_toggle_button_get_active (dialog->button_discrete)) { gint nvals = 0; gint badvals = 0; gint i; mv_clear(&dialog->mvl); for(i = 0 ; i < 3 ; ++i ) { gchar *text = g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->mv[i]))); union value v; if ( !text || strlen (g_strstrip (text)) == 0 ) { g_free (text); continue; } if ( text_to_value (text, dialog->pv, &v)) { nvals++; mv_add_value (&dialog->mvl, &v); } else badvals++; g_free (text); value_destroy (&v, var_get_width (dialog->pv)); } if ( nvals == 0 || badvals > 0 ) { err_dialog (_("Incorrect value for variable type"), GTK_WINDOW (dialog->window)); return ; } } if (gtk_toggle_button_get_active (dialog->button_range)) { gchar *discrete_text ; union value low_val ; union value high_val; const gchar *low_text = gtk_entry_get_text (GTK_ENTRY (dialog->low)); const gchar *high_text = gtk_entry_get_text (GTK_ENTRY (dialog->high)); if ( text_to_value (low_text, dialog->pv, &low_val) && text_to_value (high_text, dialog->pv, &high_val)) { if ( low_val.f > high_val.f ) { err_dialog (_("Incorrect range specification"), GTK_WINDOW (dialog->window)); value_destroy (&low_val, var_get_width (dialog->pv)); value_destroy (&high_val, var_get_width (dialog->pv)); return ; } } else { err_dialog (_("Incorrect range specification"), GTK_WINDOW (dialog->window)); value_destroy (&low_val, var_get_width (dialog->pv)); value_destroy (&high_val, var_get_width (dialog->pv)); return; } discrete_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->discrete))); mv_clear (&dialog->mvl); mv_add_range (&dialog->mvl, low_val.f, high_val.f); value_destroy (&low_val, var_get_width (dialog->pv)); value_destroy (&high_val, var_get_width (dialog->pv)); if ( discrete_text && strlen (g_strstrip (discrete_text)) > 0 ) { union value discrete_val; if ( !text_to_value (discrete_text, dialog->pv, &discrete_val)) { err_dialog (_("Incorrect value for variable type"), GTK_WINDOW (dialog->window) ); g_free (discrete_text); value_destroy (&discrete_val, var_get_width (dialog->pv)); return; } mv_add_value (&dialog->mvl, &discrete_val); value_destroy (&discrete_val, var_get_width (dialog->pv)); } g_free (discrete_text); } if (gtk_toggle_button_get_active (dialog->button_none)) mv_clear (&dialog->mvl); var_set_missing_values (dialog->pv, &dialog->mvl); gtk_widget_hide (dialog->window); }
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; }
/* 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; }