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; }
BibtexField * bibtex_reverse_field (BibtexField * field, gboolean use_braces, gboolean do_quote) { BibtexStruct * s = NULL; gchar * string, * tmp; gboolean is_upper, has_space, is_command, was_command; gint i; BibtexAuthor * author; static GString * st = NULL; static RECODE_OUTER outer = NULL; static RECODE_REQUEST request = NULL; g_return_val_if_fail (field != NULL, NULL); if (st == NULL) st = g_string_sized_new (16); if (outer == NULL) { outer = recode_new_outer (false); g_assert (outer != NULL); } if (request == NULL) { request = recode_new_request (outer); g_assert (request != NULL); if (! recode_scan_request (request, "latin1..latex")) { g_error ("can't create recoder"); } } if (field->structure) { bibtex_struct_destroy (field->structure, TRUE); field->structure = NULL; } field->loss = FALSE; switch (field->type) { case BIBTEX_OTHER: case BIBTEX_VERBATIM: g_return_val_if_fail (field->text != NULL, NULL); g_string_truncate (st, 0); if (! use_braces) { if (strchr (field->text, '"')) { use_braces = TRUE; } } if (use_braces) { g_string_append (st, "@preamble{{"); } else { g_string_append (st, "@preamble{\""); } if (do_quote) { tmp = recode_string (request, field->text); g_string_append (st, tmp); g_free (tmp); } else { g_string_append (st, field->text); } if (use_braces) { g_string_append (st, "}}"); } else { g_string_append (st, "\"}"); } s = text_to_struct (st->str); break; case BIBTEX_TITLE: g_return_val_if_fail (field->text != NULL, NULL); g_string_truncate (st, 0); if (! use_braces) { if (strchr (field->text, '"')) { use_braces = TRUE; } } tmp = recode_string (request, field->text); if (use_braces) { g_string_append (st, "@preamble{{"); } else { g_string_append (st, "@preamble{\""); } /* Put the first lower case between {} */ string = tmp; if (* tmp >= 'a' && * tmp <= 'z') { /* Put the beginning in lower cases */ g_string_append_c (st, '{'); g_string_append_c (st, * tmp); g_string_append_c (st, '}'); } else { /* The first character is done */ g_string_append_c (st, * tmp); } tmp ++; /* check for upper cases afterward */ is_upper = false; is_command = false; was_command = false; while (* tmp) { /* start a latex command */ if (* tmp == '\\') { /* eventually closes the bracket */ if (is_upper) { is_upper = false; g_string_append_c (st, '}'); } is_command = true; was_command = false; g_string_append_c (st, * tmp); tmp ++; continue; } if (is_command) { if (! ((* tmp >= 'a' && * tmp <= 'z') || (* tmp >= 'A' && * tmp <= 'Z'))) { is_command = false; was_command = true; } g_string_append_c (st, * tmp); tmp ++; continue; } if (* tmp >= 'A' && * tmp <= 'Z') { if (! is_upper) { g_string_append_c (st, '{'); g_string_append_c (st, * tmp); if (was_command) { g_string_append_c (st, '}'); } else { is_upper = true; } } else { g_string_append_c (st, * tmp); } } else { if (is_upper) { g_string_append_c (st, '}'); is_upper = false; } g_string_append_c (st, * tmp); } was_command = false; tmp ++; } /* eventually close the brackets */ if (is_upper) { g_string_append_c (st, '}'); is_upper = false; } g_free (string); if (use_braces) { g_string_append (st, "}}"); } else { g_string_append (st, "\"}"); } s = text_to_struct (st->str); break; case BIBTEX_AUTHOR: g_return_val_if_fail (field->field.author != NULL, NULL); g_string_truncate (st, 0); /* Create a simple preamble to parse */ if (! use_braces) { for (i = 0 ; i < field->field.author->len; i ++) { author = & g_array_index (field->field.author, BibtexAuthor, i); if (author->last && strchr (author->last, '"')) { use_braces = TRUE; break; } if (author->lineage && strchr (author->lineage, '"')) { use_braces = TRUE; break; } if (author->first && strchr (author->first, '"')) { use_braces = TRUE; break; } } } if (use_braces) { g_string_append (st, "@preamble{{"); } else { g_string_append (st, "@preamble{\""); } for (i = 0 ; i < field->field.author->len; i ++) { author = & g_array_index (field->field.author, BibtexAuthor, i); if (i != 0) { g_string_append (st, " and "); } if (author->last) { /* quotes if there is no first name */ has_space = author_needs_quotes (author->last) || (author->first == NULL && strpbrk (author->last, " \t") != NULL); if (has_space) { g_string_append_c (st, '{'); } tmp = recode_string (request, author->last); g_string_append (st, tmp); g_free (tmp); if (has_space) { g_string_append_c (st, '}'); } } if (author->lineage) { g_string_append (st, ", "); has_space = author_needs_quotes (author->lineage); if (has_space) { g_string_append_c (st, '{'); } tmp = recode_string (request, author->lineage); g_string_append (st, tmp); g_free (tmp); if (has_space) { g_string_append_c (st, '}'); } } if (author->first) { g_string_append (st, ", "); has_space = author_needs_quotes (author->first); if (has_space) { g_string_append_c (st, '{'); } tmp = recode_string (request, author->first); g_string_append (st, tmp); g_free (tmp); if (has_space) { g_string_append_c (st, '}'); } } } if (use_braces) { g_string_append (st, "}}"); } else { g_string_append (st, "\"}"); } s = text_to_struct (st->str); break; case BIBTEX_DATE: s = bibtex_struct_new (BIBTEX_STRUCT_TEXT); s->value.text = g_strdup_printf ("%d", field->field.date.year); break; default: g_assert_not_reached (); } field->structure = s; /* remove text field */ if (field->text) { g_free (field->text); field->text = NULL; field->converted = FALSE; } return field; }
/* 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; } }