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