Remove "Written by Ben Pfaff <blp@gnu.org>" lines everywhere.
[pspp-builds.git] / src / language / dictionary / missing-values.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17    02110-1301, USA. */
18
19 #include <config.h>
20
21 #include <stdlib.h>
22
23 #include <data/data-in.h>
24 #include <data/missing-values.h>
25 #include <data/procedure.h>
26 #include <data/value.h>
27 #include <data/variable.h>
28 #include <language/command.h>
29 #include <language/lexer/lexer.h>
30 #include <language/lexer/variable-parser.h>
31 #include <language/lexer/range-parser.h>
32 #include <libpspp/magic.h>
33 #include <libpspp/message.h>
34 #include <libpspp/message.h>
35 #include <libpspp/str.h>
36
37 #include "gettext.h"
38 #define _(msgid) gettext (msgid)
39
40 int
41 cmd_missing_values (struct lexer *lexer, struct dataset *ds)
42 {
43   struct variable **v;
44   size_t nv;
45
46   int retval = CMD_FAILURE;
47   bool deferred_errors = false;
48
49   while (lex_token (lexer) != '.')
50     {
51       size_t i;
52
53       if (!parse_variables (lexer, dataset_dict (ds), &v, &nv, PV_NONE)) 
54         goto done;
55
56       if (!lex_match (lexer, '('))
57         {
58           lex_error (lexer, _("expecting `('"));
59           goto done;
60         }
61
62       for (i = 0; i < nv; i++)
63         var_clear_missing_values (v[i]);
64
65       if (!lex_match (lexer, ')')) 
66         {
67           struct missing_values mv;
68
69           for (i = 0; i < nv; i++)
70             if (var_get_type (v[i]) != var_get_type (v[0]))
71               {
72                 const struct variable *n = var_is_numeric (v[0]) ? v[0] : v[i];
73                 const struct variable *s = var_is_numeric (v[0]) ? v[i] : v[0];
74                 msg (SE, _("Cannot mix numeric variables (e.g. %s) and "
75                            "string variables (e.g. %s) within a single list."),
76                      var_get_name (n), var_get_name (s));
77                 goto done;
78               }
79
80           if (var_is_numeric (v[0])) 
81             {
82               mv_init (&mv, 0);
83               while (!lex_match (lexer, ')'))
84                 {
85                   enum fmt_type type = var_get_print_format (v[0])->type;
86                   double x, y;
87                   bool ok;
88
89                   if (!parse_num_range (lexer, &x, &y, &type))
90                     goto done;
91                   
92                   ok = (x == y
93                         ? mv_add_num (&mv, x)
94                         : mv_add_num_range (&mv, x, y));
95                   if (!ok)
96                     deferred_errors = true;
97
98                   lex_match (lexer, ',');
99                 }
100             }
101           else 
102             {
103               struct string value;
104
105               mv_init (&mv, MAX_SHORT_STRING);
106               while (!lex_match (lexer, ')')) 
107                 {
108                   if (!lex_force_string (lexer))
109                     {
110                       deferred_errors = true;
111                       break;
112                     }
113                   
114                   ds_init_string (&value, lex_tokstr (lexer));
115
116                   if (ds_length (&value) > MAX_SHORT_STRING) 
117                     {
118                       ds_truncate (&value, MAX_SHORT_STRING);
119                       msg (SE, _("Truncating missing value to short string "
120                                  "length (%d characters)."),
121                            MAX_SHORT_STRING);
122                     }
123                   else
124                     ds_rpad (&value, MAX_SHORT_STRING, ' ');
125
126                   if (!mv_add_str (&mv, ds_data (&value)))
127                     deferred_errors = true;
128                   ds_destroy (&value);
129
130                   lex_get (lexer);
131                   lex_match (lexer, ',');
132                 }
133             }
134           
135           for (i = 0; i < nv; i++) 
136             {
137               if (mv_is_resizable (&mv, var_get_width (v[i]))) 
138                 var_set_missing_values (v[i], &mv);
139               else 
140                 {
141                   msg (SE, _("Missing values provided are too long to assign "
142                              "to variable of width %d."),
143                        var_get_width (v[i]));
144                   deferred_errors = true;
145                 }
146             }
147         }
148
149       lex_match (lexer, '/');
150       free (v);
151       v = NULL;
152     }
153   retval = lex_end_of_command (lexer);
154   
155  done:
156   free (v);
157   if (deferred_errors)
158     retval = CMD_FAILURE;
159   return retval;
160 }
161