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;
149 char buffer[FMT_MAX_NUMERIC_WIDTH];
153 data_out (&v_in, format, buffer);
155 ok = data_in (ss_buffer (buffer, format->w), LEGACY_NATIVE,
156 format->type, false, 0, 0, &v_out, 0);
158 if (ok && v_out.f == number)
160 syntax_gen_string (output, ss_buffer (buffer, format->w));
165 if (number == SYSMIS)
166 ds_put_cstr (output, "SYSMIS");
169 /* FIXME: This should consistently yield precisely the same
170 value as NUMBER on input, but its results for values
171 cannot be exactly represented in decimal are ugly: many
172 of them will have far more decimal digits than are
173 needed. The free-format floating point output routine
174 from Steele and White, "How to Print Floating-Point
175 Numbers Accurately" is really what we want. The MPFR
176 library has an implementation of this, or equivalent
177 functionality, in its mpfr_strtofr routine, but it would
178 not be nice to make PSPP depend on this. Probably, we
179 should implement something equivalent to it. */
180 ds_put_format (output, "%.*g", DBL_DIG + 1, number);
184 /* Appends to OUTPUT a representation of VALUE, which has the
185 specified WIDTH. If FORMAT is non-null, it influences the
186 output format. The representation is precise, that is, when
187 PSPP parses the representation, its value will be exactly
190 syntax_gen_value (struct string *output, const union value *value, int width,
191 const struct fmt_spec *format)
193 assert (format == NULL || fmt_var_width (format) == width);
195 syntax_gen_number (output, value->f, format);
197 syntax_gen_string (output, ss_buffer (value_str (value, width), width));
200 /* Appends <low> THRU <high> to OUTPUT. If LOW is LOWEST, then
201 it is formatted as the identifier LO; if HIGH is HIGHEST, then
202 it is formatted as the identifier HI. Otherwise, LOW and HIGH
203 are formatted as with a call to syntax_gen_num with the specified
206 This is the opposite of the function parse_num_range. */
208 syntax_gen_num_range (struct string *output, double low, double high,
209 const struct fmt_spec *format)
212 ds_put_cstr (output, "LO");
214 syntax_gen_number (output, low, format);
216 ds_put_cstr (output, " THRU ");
219 ds_put_cstr (output, "HI");
221 syntax_gen_number (output, high, format);
224 /* Same as syntax_gen_pspp, below, but takes a va_list. */
226 syntax_gen_pspp_valist (struct string *output, const char *format,
231 size_t copy = strcspn (format, "%");
232 ds_put_substring (output, ss_buffer (format, copy));
237 assert (*format == '%');
243 const char *s = va_arg (args, char *);
247 syntax_gen_string (output, ss_cstr (s));
250 ds_put_cstr (output, s);
260 int i = va_arg (args, int);
261 ds_put_format (output, "%d", i);
267 double d = va_arg (args, double);
271 ds_put_format (output, "%f", d);
280 ds_put_char (output, '%');
289 /* printf-like function specialized for outputting PSPP syntax.
290 FORMAT is appended to OUTPUT. The following substitutions are
293 %sq: The char * argument is formatted as a PSPP string, as
294 if with a call to syntax_gen_string.
296 %ss: The char * argument is appended literally.
298 %d: Same as printf's %d.
300 %fp: The double argument is formatted precisely as a PSPP
301 number, as if with a call to syntax_gen_number with a
302 null FORMAT argument.
306 (These substitutions were chosen to allow GCC to check for
307 correct argument types.)
309 This function is somewhat experimental. If it proves useful,
310 the allowed substitutions will almost certainly be
313 syntax_gen_pspp (struct string *output, const char *format, ...)
316 va_start (args, format);
317 syntax_gen_pspp_valist (output, format, args);