X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fxforms%2Fcount.c;h=9db76f6c652b11e5a12586208eb83102faa1fd51;hb=f4491cda2715c59495d963d0a3d8ae4518c1c13d;hp=38e3e955775513d340b9b01f8bfc3db95f8e7429;hpb=e9aa6e433b846849da90550f6800095d569fb549;p=pspp diff --git a/src/language/xforms/count.c b/src/language/xforms/count.c index 38e3e95577..9db76f6c65 100644 --- a/src/language/xforms/count.c +++ b/src/language/xforms/count.c @@ -1,41 +1,39 @@ -/* PSPP - computes sample statistics. - Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. - Written by Ben Pfaff . +/* PSPP - a program for statistical analysis. + Copyright (C) 1997-9, 2000, 2009, 2010, 2011, 2015 Free Software Foundation, Inc. - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. */ + along with this program. If not, see . */ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "data/case.h" +#include "data/dataset.h" +#include "data/dictionary.h" +#include "data/transformations.h" +#include "data/variable.h" +#include "language/command.h" +#include "language/lexer/lexer.h" +#include "language/lexer/value-parser.h" +#include "language/lexer/variable-parser.h" +#include "libpspp/compiler.h" +#include "libpspp/i18n.h" +#include "libpspp/message.h" +#include "libpspp/pool.h" +#include "libpspp/str.h" + +#include "gl/xalloc.h" #include "gettext.h" #define _(msgid) gettext (msgid) @@ -59,15 +57,15 @@ struct criteria struct criteria *next; /* Variables to count. */ - struct variable **vars; - size_t var_cnt; + const struct variable **vars; + size_t n_vars; - /* Count special values?. */ + /* Count special values? */ bool count_system_missing; /* Count system missing? */ bool count_user_missing; /* Count user missing? */ - /* Criterion values. */ - size_t value_cnt; + /* Criterion values. */ + size_t n_values; union { struct num_value *num; @@ -90,14 +88,16 @@ struct count_trns struct pool *pool; }; -static trns_proc_func count_trns_proc; -static trns_free_func count_trns_free; +static const struct trns_class count_trns_class; -static bool parse_numeric_criteria (struct pool *, struct criteria *); -static bool parse_string_criteria (struct pool *, struct criteria *); +static bool parse_numeric_criteria (struct lexer *, struct pool *, struct criteria *); +static bool parse_string_criteria (struct lexer *, struct pool *, + struct criteria *, + const char *dict_encoding); +static bool count_trns_free (void *trns_); int -cmd_count (void) +cmd_count (struct lexer *lexer, struct dataset *ds) { struct dst_var *dv; /* Destination var being parsed. */ struct count_trns *trns; /* Transformation. */ @@ -115,57 +115,60 @@ cmd_count (void) dv->crit = NULL; /* Get destination variable, or at least its name. */ - if (!lex_force_id ()) + if (!lex_force_id (lexer)) goto fail; - dv->var = dict_lookup_var (default_dict, tokid); + dv->var = dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer)); if (dv->var != NULL) { - if (dv->var->type == ALPHA) + if (var_is_alpha (dv->var)) { msg (SE, _("Destination cannot be a string variable.")); goto fail; } } else - dv->name = pool_strdup (trns->pool, tokid); + dv->name = pool_strdup (trns->pool, lex_tokcstr (lexer)); - lex_get (); - if (!lex_force_match ('=')) + lex_get (lexer); + if (!lex_force_match (lexer, T_EQUALS)) goto fail; crit = dv->crit = pool_alloc (trns->pool, sizeof *crit); for (;;) { + struct dictionary *dict = dataset_dict (ds); bool ok; - + crit->next = NULL; crit->vars = NULL; - if (!parse_variables (default_dict, &crit->vars, &crit->var_cnt, - PV_DUPLICATE | PV_SAME_TYPE)) + if (!parse_variables_const (lexer, dict, &crit->vars, + &crit->n_vars, + PV_DUPLICATE | PV_SAME_TYPE)) goto fail; pool_register (trns->pool, free, crit->vars); - if (!lex_force_match ('(')) + if (!lex_force_match (lexer, T_LPAREN)) goto fail; - crit->value_cnt = 0; - if (crit->vars[0]->type == NUMERIC) - ok = parse_numeric_criteria (trns->pool, crit); + crit->n_values = 0; + if (var_is_numeric (crit->vars[0])) + ok = parse_numeric_criteria (lexer, trns->pool, crit); else - ok = parse_string_criteria (trns->pool, crit); + ok = parse_string_criteria (lexer, trns->pool, crit, + dict_get_encoding (dict)); if (!ok) goto fail; - if (token == '/' || token == '.') + if (lex_token (lexer) == T_SLASH || lex_token (lexer) == T_ENDCMD) break; crit = crit->next = pool_alloc (trns->pool, sizeof *crit); } - if (token == '.') + if (lex_token (lexer) == T_ENDCMD) break; - if (!lex_force_match ('/')) + if (!lex_force_match (lexer, T_SLASH)) goto fail; dv = dv->next = pool_alloc (trns->pool, sizeof *dv); } @@ -176,13 +179,13 @@ cmd_count (void) { /* It's valid, though motivationally questionable, to count to the same dest var more than once. */ - dv->var = dict_lookup_var (default_dict, dv->name); + dv->var = dict_lookup_var (dataset_dict (ds), dv->name); - if (dv->var == NULL) - dv->var = dict_create_var_assert (default_dict, dv->name, 0); + if (dv->var == NULL) + dv->var = dict_create_var_assert (dataset_dict (ds), dv->name, 0); } - add_transformation (count_trns_proc, count_trns_free, trns); + add_transformation (ds, &count_trns_class, trns); return CMD_SUCCESS; fail: @@ -192,7 +195,7 @@ fail: /* Parses a set of numeric criterion values. Returns success. */ static bool -parse_numeric_criteria (struct pool *pool, struct criteria *crit) +parse_numeric_criteria (struct lexer *lexer, struct pool *pool, struct criteria *crit) { size_t allocated = 0; @@ -202,20 +205,20 @@ parse_numeric_criteria (struct pool *pool, struct criteria *crit) for (;;) { double low, high; - - if (lex_match_id ("SYSMIS")) + + if (lex_match_id (lexer, "SYSMIS")) crit->count_system_missing = true; - else if (lex_match_id ("MISSING")) - crit->count_user_missing = true; - else if (parse_num_range (&low, &high, NULL)) + else if (lex_match_id (lexer, "MISSING")) + crit->count_system_missing = crit->count_user_missing = true; + else if (parse_num_range (lexer, &low, &high, NULL)) { struct num_value *cur; - if (crit->value_cnt >= allocated) + if (crit->n_values >= allocated) crit->values.num = pool_2nrealloc (pool, crit->values.num, &allocated, sizeof *crit->values.num); - cur = &crit->values.num[crit->value_cnt++]; + cur = &crit->values.num[crit->n_values++]; cur->type = low == high ? CNT_SINGLE : CNT_RANGE; cur->a = low; cur->b = high; @@ -223,8 +226,8 @@ parse_numeric_criteria (struct pool *pool, struct criteria *crit) else return false; - lex_match (','); - if (lex_match (')')) + lex_match (lexer, T_COMMA); + if (lex_match (lexer, T_RPAREN)) break; } return true; @@ -232,34 +235,43 @@ parse_numeric_criteria (struct pool *pool, struct criteria *crit) /* Parses a set of string criteria values. Returns success. */ static bool -parse_string_criteria (struct pool *pool, struct criteria *crit) +parse_string_criteria (struct lexer *lexer, struct pool *pool, + struct criteria *crit, const char *dict_encoding) { int len = 0; size_t allocated = 0; size_t i; - for (i = 0; i < crit->var_cnt; i++) - if (crit->vars[i]->width > len) - len = crit->vars[i]->width; + for (i = 0; i < crit->n_vars; i++) + if (var_get_width (crit->vars[i]) > len) + len = var_get_width (crit->vars[i]); crit->values.str = NULL; for (;;) { char **cur; - if (crit->value_cnt >= allocated) + char *s; + + if (crit->n_values >= allocated) crit->values.str = pool_2nrealloc (pool, crit->values.str, &allocated, sizeof *crit->values.str); - if (!lex_force_string ()) + if (!lex_force_string (lexer)) return false; - cur = &crit->values.str[crit->value_cnt++]; + + s = recode_string (dict_encoding, "UTF-8", lex_tokcstr (lexer), + ss_length (lex_tokss (lexer))); + + cur = &crit->values.str[crit->n_values++]; *cur = pool_alloc (pool, len + 1); - str_copy_rpad (*cur, len + 1, ds_cstr (&tokstr)); - lex_get (); + str_copy_rpad (*cur, len + 1, s); + lex_get (lexer); - lex_match (','); - if (lex_match (')')) + free (s); + + lex_match (lexer, T_COMMA); + if (lex_match (lexer, T_RPAREN)) break; } @@ -269,50 +281,52 @@ parse_string_criteria (struct pool *pool, struct criteria *crit) /* Transformation. */ /* Counts the number of values in case C matching CRIT. */ -static inline int -count_numeric (struct criteria *crit, struct ccase *c) +static int +count_numeric (struct criteria *crit, const struct ccase *c) { int counter = 0; size_t i; - for (i = 0; i < crit->var_cnt; i++) + for (i = 0; i < crit->n_vars; i++) { - double x = case_num (c, crit->vars[i]->fv); - if (x == SYSMIS) - counter += crit->count_system_missing; - else if (crit->count_user_missing - && mv_is_num_user_missing (&crit->vars[i]->miss, x)) - counter++; - else + double x = case_num (c, crit->vars[i]); + struct num_value *v; + + for (v = crit->values.num; v < crit->values.num + crit->n_values; + v++) + if (v->type == CNT_SINGLE ? x == v->a : x >= v->a && x <= v->b) + { + counter++; + break; + } + + if (var_is_num_missing (crit->vars[i], x) + && (x == SYSMIS + ? crit->count_system_missing + : crit->count_user_missing)) { - struct num_value *v; - - for (v = crit->values.num; v < crit->values.num + crit->value_cnt; - v++) - if (v->type == CNT_SINGLE ? x == v->a : x >= v->a && x <= v->b) - { - counter++; - break; - } + counter++; + continue; } + } - + return counter; } /* Counts the number of values in case C matching CRIT. */ -static inline int -count_string (struct criteria *crit, struct ccase *c) +static int +count_string (struct criteria *crit, const struct ccase *c) { int counter = 0; size_t i; - for (i = 0; i < crit->var_cnt; i++) + for (i = 0; i < crit->n_vars; i++) { char **v; - for (v = crit->values.str; v < crit->values.str + crit->value_cnt; v++) - if (!memcmp (case_str (c, crit->vars[i]->fv), *v, - crit->vars[i]->width)) + for (v = crit->values.str; v < crit->values.str + crit->n_values; v++) + if (!memcmp (case_str (c, crit->vars[i]), *v, + var_get_width (crit->vars[i]))) { counter++; break; @@ -323,13 +337,14 @@ count_string (struct criteria *crit, struct ccase *c) } /* Performs the COUNT transformation T on case C. */ -static int -count_trns_proc (void *trns_, struct ccase *c, - int case_num UNUSED) +static enum trns_result +count_trns_proc (void *trns_, struct ccase **c, + casenumber case_num UNUSED) { struct count_trns *trns = trns_; struct dst_var *dv; + *c = case_unshare (*c); for (dv = trns->dst_vars; dv; dv = dv->next) { struct criteria *crit; @@ -337,11 +352,11 @@ count_trns_proc (void *trns_, struct ccase *c, counter = 0; for (crit = dv->crit; crit; crit = crit->next) - if (crit->vars[0]->type == NUMERIC) - counter += count_numeric (crit, c); + if (var_is_numeric (crit->vars[0])) + counter += count_numeric (crit, *c); else - counter += count_string (crit, c); - case_data_rw (c, dv->var->fv)->f = counter; + counter += count_string (crit, *c); + *case_num_rw (*c, dv->var) = counter; } return TRNS_CONTINUE; } @@ -350,7 +365,13 @@ count_trns_proc (void *trns_, struct ccase *c, static bool count_trns_free (void *trns_) { - struct count_trns *trns = (struct count_trns *) trns_; + struct count_trns *trns = trns_; pool_destroy (trns->pool); return true; } + +static const struct trns_class count_trns_class = { + .name = "COUNT", + .execute = count_trns_proc, + .destroy = count_trns_free, +};