1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2010 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/cast.h"
30 #include "libpspp/message.h"
31 #include "libpspp/str.h"
33 /* Appends to OUTPUT a pair of hex digits for each byte in IN. */
35 syntax_gen_hex_digits (struct string *output, struct substring in)
38 for (i = 0; i < in.length; i++)
40 unsigned char c = in.string[i];
41 ds_put_char (output, "0123456789ABCDEF"[c >> 4]);
42 ds_put_char (output, "0123456789ABCDEF"[c & 0xf]);
46 /* Returns true if IN contains any control characters, false
49 has_control_chars (struct substring in)
53 for (i = 0; i < in.length; i++)
54 if (iscntrl ((unsigned char) in.string[i]))
60 has_single_quote (struct substring str)
62 return (SIZE_MAX != ss_find_char (str, '\''));
66 has_double_quote (struct substring str)
68 return (SIZE_MAX != ss_find_char (str, '"'));
71 /* Appends to OUTPUT valid PSPP syntax for a quoted string that
74 IN must be encoded in UTF-8, and the quoted result will also
77 The string will be output as a regular quoted string unless it
78 contains control characters, in which case it is output as a
81 syntax_gen_string (struct string *output, struct substring in)
83 if (has_control_chars (in))
85 ds_put_cstr (output, "X'");
86 syntax_gen_hex_digits (output, in);
87 ds_put_char (output, '\'');
94 /* This seemingly simple implementation is possible, because UTF-8
95 guarantees that bytes corresponding to basic characters (such as
96 '\'') cannot appear in a multi-byte character sequence except to
97 represent that basic character.
99 assert (is_basic ('\''));
101 quote = has_double_quote (in) && !has_single_quote (in) ? '\'' : '"';
102 ds_put_char (output, quote);
103 for (i = 0; i < in.length; i++)
105 char c = in.string[i];
107 ds_put_char (output, quote);
108 ds_put_char (output, c);
110 ds_put_char (output, quote);
114 /* Appends to OUTPUT a representation of NUMBER in PSPP syntax.
115 The representation is precise, that is, when PSPP parses the
116 representation, its value will be exactly NUMBER. (This might
117 not be the case on a C implementation where double has a
118 different representation.)
120 If NUMBER is the system-missing value, it is output as the
121 identifier SYSMIS. This may not be appropriate, because
122 SYSMIS is not consistently parsed throughout PSPP syntax as
123 the system-missing value. But in such circumstances the
124 system-missing value would not be meaningful anyhow, so the
125 caller should refrain from supplying the system-missing value
128 A value of LOWEST or HIGHEST is not treated specially.
130 If FORMAT is null, then the representation will be in numeric
131 form, e.g. 123 or 1.23e10.
133 If FORMAT is non-null, then it must point to a numeric format.
134 If the format is one easier for a user to understand when
135 expressed as a string than as a number (for example, a date
136 format), and the string representation precisely represents
137 NUMBER, then the string representation is written to OUTPUT.
138 Otherwise, NUMBER is output as if FORMAT was a null
141 syntax_gen_number (struct string *output,
142 double number, const struct fmt_spec *format)
144 assert (format == NULL || fmt_is_numeric (format->type));
147 & (FMT_CAT_DATE | FMT_CAT_TIME | FMT_CAT_DATE_COMPONENT)))
149 union value v_in, v_out;
154 s = data_out (&v_in, "FIXME", format);
156 /* FIXME: UTF8 encoded strings will fail here */
157 ok = data_in (ss_cstr (s), LEGACY_NATIVE,
158 format->type, false, 0, 0, NULL, &v_out, 0);
160 if (ok && v_out.f == number)
162 syntax_gen_string (output, ss_cstr (s));
169 if (number == SYSMIS)
170 ds_put_cstr (output, "SYSMIS");
173 /* FIXME: This should consistently yield precisely the same
174 value as NUMBER on input, but its results for values
175 cannot be exactly represented in decimal are ugly: many
176 of them will have far more decimal digits than are
177 needed. The free-format floating point output routine
178 from Steele and White, "How to Print Floating-Point
179 Numbers Accurately" is really what we want. The MPFR
180 library has an implementation of this, or equivalent
181 functionality, in its mpfr_strtofr routine, but it would
182 not be nice to make PSPP depend on this. Probably, we
183 should implement something equivalent to it. */
184 ds_put_format (output, "%.*g", DBL_DIG + 1, number);
188 /* Appends to OUTPUT a representation of VALUE, which has the
189 specified WIDTH. If FORMAT is non-null, it influences the
190 output format. The representation is precise, that is, when
191 PSPP parses the representation, its value will be exactly
194 syntax_gen_value (struct string *output, const union value *value, int width,
195 const struct fmt_spec *format)
197 assert (format == NULL || fmt_var_width (format) == width);
199 syntax_gen_number (output, value->f, format);
202 char *s = CHAR_CAST_BUG (char *, value_str (value, width));
203 syntax_gen_string (output, ss_buffer (s, width));
207 /* Appends <low> THRU <high> to OUTPUT. If LOW is LOWEST, then
208 it is formatted as the identifier LO; if HIGH is HIGHEST, then
209 it is formatted as the identifier HI. Otherwise, LOW and HIGH
210 are formatted as with a call to syntax_gen_num with the specified
213 This is the opposite of the function parse_num_range. */
215 syntax_gen_num_range (struct string *output, double low, double high,
216 const struct fmt_spec *format)
219 ds_put_cstr (output, "LO");
221 syntax_gen_number (output, low, format);
223 ds_put_cstr (output, " THRU ");
226 ds_put_cstr (output, "HI");
228 syntax_gen_number (output, high, format);
231 /* Same as syntax_gen_pspp, below, but takes a va_list. */
233 syntax_gen_pspp_valist (struct string *output, const char *format,
238 size_t copy = strcspn (format, "%");
239 ds_put_substring (output, ss_buffer (format, copy));
244 assert (*format == '%');
250 const char *s = va_arg (args, char *);
254 syntax_gen_string (output, ss_cstr (s));
257 ds_put_cstr (output, s);
267 int i = va_arg (args, int);
268 ds_put_format (output, "%d", i);
274 double d = va_arg (args, double);
278 ds_put_format (output, "%f", d);
287 ds_put_char (output, '%');
296 /* printf-like function specialized for outputting PSPP syntax.
297 FORMAT is appended to OUTPUT. The following substitutions are
300 %sq: The char * argument is formatted as a PSPP string, as
301 if with a call to syntax_gen_string.
303 %ss: The char * argument is appended literally.
305 %d: Same as printf's %d.
307 %fp: The double argument is formatted precisely as a PSPP
308 number, as if with a call to syntax_gen_number with a
309 null FORMAT argument.
313 (These substitutions were chosen to allow GCC to check for
314 correct argument types.)
316 This function is somewhat experimental. If it proves useful,
317 the allowed substitutions will almost certainly be
320 syntax_gen_pspp (struct string *output, const char *format, ...)
323 va_start (args, format);
324 syntax_gen_pspp_valist (output, format, args);