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)); }
/* 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)); } }
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; }
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); } }
/* 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)); } }
/* 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; }
/* 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; } }