21 |
#include "error.h" |
#include "error.h" |
22 |
#include <stdlib.h> |
#include <stdlib.h> |
23 |
#include "command.h" |
#include "command.h" |
24 |
|
#include "data-in.h" |
25 |
#include "error.h" |
#include "error.h" |
26 |
#include "lexer.h" |
#include "lexer.h" |
27 |
#include "magic.h" |
#include "magic.h" |
33 |
|
|
34 |
#include "debug-print.h" |
#include "debug-print.h" |
35 |
|
|
36 |
/* Variables on MIS VAL. */ |
static bool parse_number (double *, const struct fmt_spec *); |
|
static struct variable **v; |
|
|
static int nv; |
|
|
|
|
|
/* Type of the variables on MIS VAL. */ |
|
|
static int type; |
|
|
|
|
|
/* Width of string variables on MIS VAL. */ |
|
|
static size_t width; |
|
|
|
|
|
/* Items to fill-in var structs with. */ |
|
|
static int miss_type; |
|
|
static union value missing[3]; |
|
|
|
|
|
static int parse_varnames (void); |
|
|
static int parse_numeric (void); |
|
|
static int parse_alpha (void); |
|
37 |
|
|
38 |
int |
int |
39 |
cmd_missing_values (void) |
cmd_missing_values (void) |
40 |
{ |
{ |
41 |
int i; |
struct variable **v; |
42 |
|
int nv; |
43 |
|
|
44 |
|
int retval = CMD_PART_SUCCESS_MAYBE; |
45 |
|
bool deferred_errors = false; |
46 |
|
|
47 |
while (token != '.') |
while (token != '.') |
48 |
{ |
{ |
49 |
if (!parse_varnames ()) |
int i; |
50 |
goto fail; |
|
51 |
|
|
52 |
|
if (!parse_variables (default_dict, &v, &nv, PV_NONE)) |
53 |
|
goto done; |
54 |
|
|
55 |
if (token != ')') |
if (!lex_match ('(')) |
56 |
{ |
{ |
57 |
if ((type == NUMERIC && !parse_numeric ()) |
lex_error (_("expecting `('")); |
58 |
|| (type == ALPHA && !parse_alpha ())) |
goto done; |
59 |
goto fail; |
} |
|
} |
|
|
else |
|
|
miss_type = MISSING_NONE; |
|
|
|
|
|
if (!lex_match (')')) |
|
|
{ |
|
|
msg (SE, _("`)' expected after value specification.")); |
|
|
goto fail; |
|
|
} |
|
60 |
|
|
61 |
for (i = 0; i < nv; i++) |
for (i = 0; i < nv; i++) |
62 |
{ |
mv_init (&v[i]->miss, v[i]->width); |
63 |
v[i]->miss_type = miss_type; |
|
64 |
memcpy (v[i]->missing, missing, sizeof v[i]->missing); |
if (!lex_match (')')) |
65 |
} |
{ |
66 |
|
struct missing_values mv; |
67 |
|
|
68 |
|
for (i = 0; i < nv; i++) |
69 |
|
if (v[i]->type != v[0]->type) |
70 |
|
{ |
71 |
|
const struct variable *n = v[0]->type == NUMERIC ? v[0] : v[i]; |
72 |
|
const struct variable *s = v[0]->type == NUMERIC ? v[i] : v[0]; |
73 |
|
msg (SE, _("Cannot mix numeric variables (e.g. %s) and " |
74 |
|
"string variables (e.g. %s) within a single list."), |
75 |
|
n->name, s->name); |
76 |
|
goto done; |
77 |
|
} |
78 |
|
|
79 |
|
if (v[0]->type == NUMERIC) |
80 |
|
{ |
81 |
|
mv_init (&mv, 0); |
82 |
|
while (!lex_match (')')) |
83 |
|
{ |
84 |
|
double x; |
85 |
|
|
86 |
|
if (lex_match_id ("LO") || lex_match_id ("LOWEST")) |
87 |
|
x = LOWEST; |
88 |
|
else if (!parse_number (&x, &v[0]->print)) |
89 |
|
goto done; |
90 |
|
|
91 |
|
if (lex_match_id ("THRU")) |
92 |
|
{ |
93 |
|
double y; |
94 |
|
|
95 |
|
if (lex_match_id ("HI") || lex_match_id ("HIGHEST")) |
96 |
|
y = HIGHEST; |
97 |
|
else if (!parse_number (&y, &v[0]->print)) |
98 |
|
goto done; |
99 |
|
|
100 |
|
if (x == LOWEST && y == HIGHEST) |
101 |
|
{ |
102 |
|
msg (SE, _("LO THRU HI is an invalid range.")); |
103 |
|
deferred_errors = true; |
104 |
|
} |
105 |
|
else if (!mv_add_num_range (&mv, x, y)) |
106 |
|
deferred_errors = true; |
107 |
|
} |
108 |
|
else |
109 |
|
{ |
110 |
|
if (x == LOWEST) |
111 |
|
{ |
112 |
|
msg (SE, _("LO or LOWEST must be part of a range.")); |
113 |
|
deferred_errors = true; |
114 |
|
} |
115 |
|
else if (!mv_add_num (&mv, x)) |
116 |
|
deferred_errors = true; |
117 |
|
} |
118 |
|
|
119 |
|
lex_match (','); |
120 |
|
} |
121 |
|
} |
122 |
|
else |
123 |
|
{ |
124 |
|
mv_init (&mv, MAX_SHORT_STRING); |
125 |
|
while (!lex_match (')')) |
126 |
|
{ |
127 |
|
if (!lex_force_string ()) |
128 |
|
{ |
129 |
|
deferred_errors = true; |
130 |
|
break; |
131 |
|
} |
132 |
|
|
133 |
|
if (ds_length (&tokstr) > MAX_SHORT_STRING) |
134 |
|
{ |
135 |
|
ds_truncate (&tokstr, MAX_SHORT_STRING); |
136 |
|
msg (SE, _("Truncating missing value to short string " |
137 |
|
"length (%d characters)."), |
138 |
|
MAX_SHORT_STRING); |
139 |
|
} |
140 |
|
else |
141 |
|
ds_rpad (&tokstr, MAX_SHORT_STRING, ' '); |
142 |
|
|
143 |
|
if (!mv_add_str (&mv, ds_data (&tokstr))) |
144 |
|
deferred_errors = true; |
145 |
|
|
146 |
|
lex_get (); |
147 |
|
lex_match (','); |
148 |
|
} |
149 |
|
} |
150 |
|
|
151 |
|
for (i = 0; i < nv; i++) |
152 |
|
{ |
153 |
|
if (!mv_is_resizable (&mv, v[i]->width)) |
154 |
|
{ |
155 |
|
msg (SE, _("Missing values provided are too long to assign " |
156 |
|
"to variable of width %d."), |
157 |
|
v[i]->width); |
158 |
|
deferred_errors = true; |
159 |
|
} |
160 |
|
else |
161 |
|
{ |
162 |
|
mv_copy (&v[i]->miss, &mv); |
163 |
|
mv_resize (&v[i]->miss, v[i]->width); |
164 |
|
} |
165 |
|
} |
166 |
|
} |
167 |
|
|
168 |
lex_match ('/'); |
lex_match ('/'); |
169 |
free (v); |
free (v); |
170 |
|
v = NULL; |
171 |
} |
} |
172 |
|
retval = lex_end_of_command (); |
173 |
return lex_end_of_command (); |
|
174 |
|
done: |
|
fail: |
|
175 |
free (v); |
free (v); |
176 |
return CMD_PART_SUCCESS_MAYBE; |
if (deferred_errors) |
177 |
} |
retval = CMD_PART_SUCCESS_MAYBE; |
178 |
|
return retval; |
|
static int |
|
|
parse_varnames (void) |
|
|
{ |
|
|
int i; |
|
|
|
|
|
if (!parse_variables (default_dict, &v, &nv, PV_SAME_TYPE)) |
|
|
return 0; |
|
|
if (!lex_match ('(')) |
|
|
{ |
|
|
msg (SE, _("`(' expected after variable name%s."), nv > 1 ? "s" : ""); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
type = v[0]->type; |
|
|
if (type == NUMERIC) |
|
|
return 1; |
|
|
|
|
|
width = v[0]->width; |
|
|
for (i = 1; i < nv; i++) |
|
|
if (v[i]->type == ALPHA && v[i]->nv != 1) |
|
|
{ |
|
|
msg (SE, _("Long string value specified.")); |
|
|
return 0; |
|
|
} |
|
|
else if (v[i]->type == ALPHA && (int) width != v[i]->width) |
|
|
{ |
|
|
msg (SE, _("Short strings must be of equal width.")); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
return 1; |
|
179 |
} |
} |
180 |
|
|
181 |
/* Number or range? */ |
static bool |
182 |
enum |
parse_number (double *x, const struct fmt_spec *f) |
|
{ |
|
|
MV_NOR_NOTHING, /* Empty. */ |
|
|
MV_NOR_NUMBER, /* Single number. */ |
|
|
MV_NOR_RANGE /* Range. */ |
|
|
}; |
|
|
|
|
|
/* A single value or a range. */ |
|
|
struct num_or_range |
|
|
{ |
|
|
int type; /* One of NOR_*. */ |
|
|
double d[2]; /* d[0]=lower bound or value, d[1]=upper bound. */ |
|
|
}; |
|
|
|
|
|
/* Parses something of the form <num>, or LO[WEST] THRU <num>, or |
|
|
<num> THRU HI[GHEST], or <num> THRU <num>, and sets the appropriate |
|
|
members of NOR. Returns success. */ |
|
|
static int |
|
|
parse_num_or_range (struct num_or_range * nor) |
|
183 |
{ |
{ |
184 |
if (lex_match_id ("LO") || lex_match_id ("LOWEST")) |
if (lex_is_number ()) |
185 |
{ |
{ |
186 |
nor->type = MV_NOR_RANGE; |
*x = lex_number (); |
|
if (!lex_force_match_id ("THRU")) |
|
|
return 0; |
|
|
if (!lex_force_num ()) |
|
|
return 0; |
|
|
nor->d[0] = LOWEST; |
|
|
nor->d[1] = tokval; |
|
|
} |
|
|
else if (lex_is_number ()) |
|
|
{ |
|
|
nor->d[0] = tokval; |
|
187 |
lex_get (); |
lex_get (); |
188 |
|
return true; |
|
if (lex_match_id ("THRU")) |
|
|
{ |
|
|
nor->type = MV_NOR_RANGE; |
|
|
if (lex_match_id ("HI") || lex_match_id ("HIGHEST")) |
|
|
nor->d[1] = HIGHEST; |
|
|
else |
|
|
{ |
|
|
if (!lex_force_num ()) |
|
|
return 0; |
|
|
nor->d[1] = tokval; |
|
|
lex_get (); |
|
|
|
|
|
if (nor->d[0] > nor->d[1]) |
|
|
{ |
|
|
msg (SE, _("Range %g THRU %g is not valid because %g is " |
|
|
"greater than %g."), |
|
|
nor->d[0], nor->d[1], nor->d[0], nor->d[1]); |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
} |
|
|
else |
|
|
nor->type = MV_NOR_NUMBER; |
|
|
} |
|
|
else |
|
|
return -1; |
|
|
|
|
|
return 1; |
|
|
} |
|
|
|
|
|
/* Parses a set of numeric missing values and stores them into |
|
|
`missing[]' and `miss_type' global variables. */ |
|
|
static int |
|
|
parse_numeric (void) |
|
|
{ |
|
|
struct num_or_range set[3]; |
|
|
int r; |
|
|
|
|
|
set[1].type = set[2].type = MV_NOR_NOTHING; |
|
|
|
|
|
/* Get first number or range. */ |
|
|
r = parse_num_or_range (&set[0]); |
|
|
if (r < 1) |
|
|
{ |
|
|
if (r == -1) |
|
|
msg (SE, _("Number or range expected.")); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
/* Get second and third optional number or range. */ |
|
|
lex_match (','); |
|
|
r = parse_num_or_range (&set[1]); |
|
|
if (r == 1) |
|
|
{ |
|
|
lex_match (','); |
|
|
r = parse_num_or_range (&set[2]); |
|
|
} |
|
|
if (r == 0) |
|
|
return 0; |
|
|
|
|
|
/* Force range, if present, into set[0]. */ |
|
|
if (set[1].type == MV_NOR_RANGE) |
|
|
{ |
|
|
struct num_or_range t = set[1]; |
|
|
set[1] = set[0]; |
|
|
set[0] = t; |
|
|
} |
|
|
if (set[2].type == MV_NOR_RANGE) |
|
|
{ |
|
|
struct num_or_range t = set[2]; |
|
|
set[2] = set[0]; |
|
|
set[0] = t; |
|
|
} |
|
|
|
|
|
/* Ensure there's not more than one range, or one range |
|
|
plus one value. */ |
|
|
if (set[1].type == MV_NOR_RANGE || set[2].type == MV_NOR_RANGE) |
|
|
{ |
|
|
msg (SE, _("At most one range can exist in the missing values " |
|
|
"for any one variable.")); |
|
|
return 0; |
|
189 |
} |
} |
190 |
if (set[0].type == MV_NOR_RANGE && set[2].type != MV_NOR_NOTHING) |
else if (token == T_STRING) |
191 |
{ |
{ |
192 |
msg (SE, _("At most one individual value can be missing along " |
struct data_in di; |
193 |
"with one range.")); |
union value v; |
194 |
return 0; |
di.s = ds_data (&tokstr); |
195 |
} |
di.e = ds_end (&tokstr); |
196 |
|
di.v = &v; |
197 |
/* Set missing[] from set[]. */ |
di.flags = 0; |
198 |
if (set[0].type == MV_NOR_RANGE) |
di.f1 = 1; |
199 |
{ |
di.f2 = ds_length (&tokstr); |
200 |
int x = 0; |
di.format = *f; |
201 |
|
data_in (&di); |
|
if (set[0].d[0] == LOWEST) |
|
|
{ |
|
|
miss_type = MISSING_LOW; |
|
|
missing[x++].f = set[0].d[1]; |
|
|
} |
|
|
else if (set[0].d[1] == HIGHEST) |
|
|
{ |
|
|
miss_type = MISSING_HIGH; |
|
|
missing[x++].f = set[0].d[0]; |
|
|
} |
|
|
else |
|
|
{ |
|
|
miss_type = MISSING_RANGE; |
|
|
missing[x++].f = set[0].d[0]; |
|
|
missing[x++].f = set[0].d[1]; |
|
|
} |
|
|
|
|
|
if (set[1].type == MV_NOR_NUMBER) |
|
|
{ |
|
|
miss_type += 3; |
|
|
missing[x].f = set[1].d[0]; |
|
|
} |
|
|
} |
|
|
else |
|
|
{ |
|
|
if (set[0].type == MV_NOR_NUMBER) |
|
|
{ |
|
|
miss_type = MISSING_1; |
|
|
missing[0].f = set[0].d[0]; |
|
|
} |
|
|
if (set[1].type == MV_NOR_NUMBER) |
|
|
{ |
|
|
miss_type = MISSING_2; |
|
|
missing[1].f = set[1].d[0]; |
|
|
} |
|
|
if (set[2].type == MV_NOR_NUMBER) |
|
|
{ |
|
|
miss_type = MISSING_3; |
|
|
missing[2].f = set[2].d[0]; |
|
|
} |
|
|
} |
|
|
|
|
|
return 1; |
|
|
} |
|
|
|
|
|
static int |
|
|
parse_alpha (void) |
|
|
{ |
|
|
for (miss_type = 0; token == T_STRING && miss_type < 3; miss_type++) |
|
|
{ |
|
|
if (ds_length (&tokstr) != width) |
|
|
{ |
|
|
msg (SE, _("String is not of proper length.")); |
|
|
return 0; |
|
|
} |
|
|
strncpy (missing[miss_type].s, ds_c_str (&tokstr), MAX_SHORT_STRING); |
|
202 |
lex_get (); |
lex_get (); |
203 |
lex_match (','); |
*x = v.f; |
204 |
|
return true; |
205 |
} |
} |
206 |
if (miss_type < 1) |
else |
207 |
{ |
{ |
208 |
msg (SE, _("String expected.")); |
lex_error (_("expecting number or data string")); |
209 |
return 0; |
return false; |
210 |
} |
} |
|
|
|
|
return 1; |
|
211 |
} |
} |
212 |
|
|
|
/* Copy the missing values from variable SRC to variable DEST. */ |
|
|
void |
|
|
copy_missing_values (struct variable *dest, const struct variable *src) |
|
|
{ |
|
|
static const int n_values[MISSING_COUNT] = |
|
|
{ |
|
|
0, 1, 2, 3, 2, 1, 1, 3, 2, 2, |
|
|
}; |
|
|
|
|
|
assert (dest->width == src->width); |
|
|
assert (src->miss_type >= 0 && src->miss_type < MISSING_COUNT); |
|
|
|
|
|
{ |
|
|
int i; |
|
|
|
|
|
dest->miss_type = src->miss_type; |
|
|
for (i = 0; i < n_values[src->miss_type]; i++) |
|
|
if (src->type == NUMERIC) |
|
|
dest->missing[i].f = src->missing[i].f; |
|
|
else |
|
|
memcpy (dest->missing[i].s, src->missing[i].s, src->width); |
|
|
} |
|
|
} |
|