Continue reforming procedure execution. In this phase, get rid of
[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
22 #include <stdlib.h>
23
24 #include <data/data-in.h>
25 #include <procedure.h>
26 #include <data/variable.h>
27 #include <language/command.h>
28 #include <language/lexer/lexer.h>
29 #include <language/lexer/range-parser.h>
30 #include <libpspp/magic.h>
31 #include <libpspp/message.h>
32 #include <libpspp/message.h>
33 #include <libpspp/str.h>
34
35 #include "gettext.h"
36 #define _(msgid) gettext (msgid)
37
38 int
39 cmd_missing_values (void)
40 {
41   struct variable **v;
42   size_t nv;
43
44   int retval = CMD_FAILURE;
45   bool deferred_errors = false;
46
47   while (token != '.')
48     {
49       size_t i;
50
51       if (!parse_variables (default_dict, &v, &nv, PV_NONE)) 
52         goto done;
53
54       if (!lex_match ('('))
55         {
56           lex_error (_("expecting `('"));
57           goto done;
58         }
59
60       for (i = 0; i < nv; i++)
61         mv_init (&v[i]->miss, v[i]->width);
62
63       if (!lex_match (')')) 
64         {
65           struct missing_values mv;
66
67           for (i = 0; i < nv; i++)
68             if (v[i]->type != v[0]->type)
69               {
70                 const struct variable *n = v[0]->type == NUMERIC ? v[0] : v[i];
71                 const struct variable *s = v[0]->type == NUMERIC ? v[i] : v[0];
72                 msg (SE, _("Cannot mix numeric variables (e.g. %s) and "
73                            "string variables (e.g. %s) within a single list."),
74                      n->name, s->name);
75                 goto done;
76               }
77
78           if (v[0]->type == NUMERIC) 
79             {
80               mv_init (&mv, 0);
81               while (!lex_match (')'))
82                 {
83                   double x, y;
84                   bool ok;
85
86                   if (!parse_num_range (&x, &y, &v[0]->print))
87                     goto done;
88                   
89                   ok = (x == y
90                         ? mv_add_num (&mv, x)
91                         : mv_add_num_range (&mv, x, y));
92                   if (!ok)
93                     deferred_errors = true;
94
95                   lex_match (',');
96                 }
97             }
98           else 
99             {
100               mv_init (&mv, MAX_SHORT_STRING);
101               while (!lex_match (')')) 
102                 {
103                   if (!lex_force_string ())
104                     {
105                       deferred_errors = true;
106                       break;
107                     }
108
109                   if (ds_length (&tokstr) > MAX_SHORT_STRING) 
110                     {
111                       ds_truncate (&tokstr, MAX_SHORT_STRING);
112                       msg (SE, _("Truncating missing value to short string "
113                                  "length (%d characters)."),
114                            MAX_SHORT_STRING);
115                     }
116                   else
117                     ds_rpad (&tokstr, MAX_SHORT_STRING, ' ');
118
119                   if (!mv_add_str (&mv, ds_data (&tokstr)))
120                     deferred_errors = true;
121
122                   lex_get ();
123                   lex_match (',');
124                 }
125             }
126           
127           for (i = 0; i < nv; i++) 
128             {
129               if (!mv_is_resizable (&mv, v[i]->width)) 
130                 {
131                   msg (SE, _("Missing values provided are too long to assign "
132                              "to variable of width %d."),
133                        v[i]->width);
134                   deferred_errors = true;
135                 }
136               else 
137                 {
138                   mv_copy (&v[i]->miss, &mv);
139                   mv_resize (&v[i]->miss, v[i]->width);
140                 }
141             }
142         }
143
144       lex_match ('/');
145       free (v);
146       v = NULL;
147     }
148   retval = lex_end_of_command ();
149   
150  done:
151   free (v);
152   if (deferred_errors)
153     retval = CMD_FAILURE;
154   return retval;
155 }
156