1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include <ui/syntax-gen.h>
24 #include <data/data-in.h>
25 #include <data/data-out.h>
26 #include <data/format.h>
27 #include <data/value.h>
28 #include <libpspp/assertion.h>
29 #include <libpspp/message.h>
30 #include <libpspp/str.h>
32 /* Appends to OUTPUT a pair of hex digits for each byte in IN. */
34 syntax_gen_hex_digits (struct string *output, struct substring in)
37 for (i = 0; i < in.length; i++)
39 unsigned char c = in.string[i];
40 ds_put_char (output, "0123456789ABCDEF"[c >> 4]);
41 ds_put_char (output, "0123456789ABCDEF"[c & 0xf]);
45 /* Returns true if IN contains any control characters, false
48 has_control_chars (struct substring in)
52 for (i = 0; i < in.length; i++)
53 if (iscntrl ((unsigned char) in.string[i]))
59 has_single_quote (struct substring str)
61 return (SIZE_MAX != ss_find_char (str, '\''));
65 has_double_quote (struct substring str)
67 return (SIZE_MAX != ss_find_char (str, '"'));
70 /* Appends to OUTPUT valid PSPP syntax for a quoted string that
73 IN must be encoded in UTF-8, and the quoted result will also
76 The string will be output as a regular quoted string unless it
77 contains control characters, in which case it is output as a
80 syntax_gen_string (struct string *output, struct substring in)
82 if (has_control_chars (in))
84 ds_put_cstr (output, "X'");
85 syntax_gen_hex_digits (output, in);
86 ds_put_char (output, '\'');
93 /* This seemingly simple implementation is possible, because UTF-8
94 guarantees that bytes corresponding to basic characters (such as
95 '\'') cannot appear in a multi-byte character sequence except to
96 represent that basic character.
98 assert (is_basic ('\''));
100 quote = has_double_quote (in) && !has_single_quote (in) ? '\'' : '"';
101 ds_put_char (output, quote);
102 for (i = 0; i < in.length; i++)
104 char c = in.string[i];
106 ds_put_char (output, quote);
107 ds_put_char (output, c);
109 ds_put_char (output, quote);
113 /* Appends to OUTPUT a representation of NUMBER in PSPP syntax.
114 The representation is precise, that is, when PSPP parses the
115 representation, its value will be exactly NUMBER. (This might
116 not be the case on a C implementation where double has a
117 different representation.)
119 If NUMBER is the system-missing value, it is output as the
120 identifier SYSMIS. This may not be appropriate, because
121 SYSMIS is not consistently parsed throughout PSPP syntax as
122 the system-missing value. But in such circumstances the
123 system-missing value would not be meaningful anyhow, so the
124 caller should refrain from supplying the system-missing value
127 A value of LOWEST or HIGHEST is not treated specially.
129 If FORMAT is null, then the representation will be in numeric
130 form, e.g. 123 or 1.23e10.
132 If FORMAT is non-null, then it must point to a numeric format.
133 If the format is one easier for a user to understand when
134 expressed as a string than as a number (for example, a date
135 format), and the string representation precisely represents
136 NUMBER, then the string representation is written to OUTPUT.
137 Otherwise, NUMBER is output as if FORMAT was a null
140 syntax_gen_number (struct string *output,
141 double number, const struct fmt_spec *format)
143 assert (format == NULL || fmt_is_numeric (format->type));
146 & (FMT_CAT_DATE | FMT_CAT_TIME | FMT_CAT_DATE_COMPONENT)))
148 union value v_in, v_out;
153 s = data_out (&v_in, "FIXME", format);
155 /* FIXME: UTF8 encoded strings will fail here */
156 ok = data_in (ss_cstr (s), LEGACY_NATIVE,
157 format->type, false, 0, 0, NULL, &v_out, 0);
159 if (ok && v_out.f == number)
161 syntax_gen_string (output, ss_cstr (s));
168 if (number == SYSMIS)
169 ds_put_cstr (output, "SYSMIS");
172 /* FIXME: This should consistently yield precisely the same
173 value as NUMBER on input, but its results for values
174 cannot be exactly represented in decimal are ugly: many
175 of them will have far more decimal digits than are
176 needed. The free-format floating point output routine
177 from Steele and White, "How to Print Floating-Point
178 Numbers Accurately" is really what we want. The MPFR
179 library has an implementation of this, or equivalent
180 functionality, in its mpfr_strtofr routine, but it would
181 not be nice to make PSPP depend on this. Probably, we
182 should implement something equivalent to it. */
183 ds_put_format (output, "%.*g", DBL_DIG + 1, number);
187 /* Appends to OUTPUT a representation of VALUE, which has the
188 specified WIDTH. If FORMAT is non-null, it influences the
189 output format. The representation is precise, that is, when
190 PSPP parses the representation, its value will be exactly
193 syntax_gen_value (struct string *output, const union value *value, int width,
194 const struct fmt_spec *format)
196 assert (format == NULL || fmt_var_width (format) == width);
198 syntax_gen_number (output, value->f, format);
200 syntax_gen_string (output, ss_buffer (value_str (value, width), width));
203 /* Appends <low> THRU <high> to OUTPUT. If LOW is LOWEST, then
204 it is formatted as the identifier LO; if HIGH is HIGHEST, then
205 it is formatted as the identifier HI. Otherwise, LOW and HIGH
206 are formatted as with a call to syntax_gen_num with the specified
209 This is the opposite of the function parse_num_range. */
211 syntax_gen_num_range (struct string *output, double low, double high,
212 const struct fmt_spec *format)
215 ds_put_cstr (output, "LO");
217 syntax_gen_number (output, low, format);
219 ds_put_cstr (output, " THRU ");
222 ds_put_cstr (output, "HI");
224 syntax_gen_number (output, high, format);
227 /* Same as syntax_gen_pspp, below, but takes a va_list. */
229 syntax_gen_pspp_valist (struct string *output, const char *format,
234 size_t copy = strcspn (format, "%");
235 ds_put_substring (output, ss_buffer (format, copy));
240 assert (*format == '%');
246 const char *s = va_arg (args, char *);
250 syntax_gen_string (output, ss_cstr (s));
253 ds_put_cstr (output, s);
263 int i = va_arg (args, int);
264 ds_put_format (output, "%d", i);
270 double d = va_arg (args, double);
274 ds_put_format (output, "%f", d);
283 ds_put_char (output, '%');
292 /* printf-like function specialized for outputting PSPP syntax.
293 FORMAT is appended to OUTPUT. The following substitutions are
296 %sq: The char * argument is formatted as a PSPP string, as
297 if with a call to syntax_gen_string.
299 %ss: The char * argument is appended literally.
301 %d: Same as printf's %d.
303 %fp: The double argument is formatted precisely as a PSPP
304 number, as if with a call to syntax_gen_number with a
305 null FORMAT argument.
309 (These substitutions were chosen to allow GCC to check for
310 correct argument types.)
312 This function is somewhat experimental. If it proves useful,
313 the allowed substitutions will almost certainly be
316 syntax_gen_pspp (struct string *output, const char *format, ...)
319 va_start (args, format);
320 syntax_gen_pspp_valist (output, format, args);