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 ok = data_in (ss_cstr (s), LEGACY_NATIVE,
156 format->type, false, 0, 0, &v_out, 0);
158 if (ok && v_out.f == number)
160 syntax_gen_string (output, ss_cstr (s));
167 if (number == SYSMIS)
168 ds_put_cstr (output, "SYSMIS");
171 /* FIXME: This should consistently yield precisely the same
172 value as NUMBER on input, but its results for values
173 cannot be exactly represented in decimal are ugly: many
174 of them will have far more decimal digits than are
175 needed. The free-format floating point output routine
176 from Steele and White, "How to Print Floating-Point
177 Numbers Accurately" is really what we want. The MPFR
178 library has an implementation of this, or equivalent
179 functionality, in its mpfr_strtofr routine, but it would
180 not be nice to make PSPP depend on this. Probably, we
181 should implement something equivalent to it. */
182 ds_put_format (output, "%.*g", DBL_DIG + 1, number);
186 /* Appends to OUTPUT a representation of VALUE, which has the
187 specified WIDTH. If FORMAT is non-null, it influences the
188 output format. The representation is precise, that is, when
189 PSPP parses the representation, its value will be exactly
192 syntax_gen_value (struct string *output, const union value *value, int width,
193 const struct fmt_spec *format)
195 assert (format == NULL || fmt_var_width (format) == width);
197 syntax_gen_number (output, value->f, format);
199 syntax_gen_string (output, ss_buffer (value_str (value, width), width));
202 /* Appends <low> THRU <high> to OUTPUT. If LOW is LOWEST, then
203 it is formatted as the identifier LO; if HIGH is HIGHEST, then
204 it is formatted as the identifier HI. Otherwise, LOW and HIGH
205 are formatted as with a call to syntax_gen_num with the specified
208 This is the opposite of the function parse_num_range. */
210 syntax_gen_num_range (struct string *output, double low, double high,
211 const struct fmt_spec *format)
214 ds_put_cstr (output, "LO");
216 syntax_gen_number (output, low, format);
218 ds_put_cstr (output, " THRU ");
221 ds_put_cstr (output, "HI");
223 syntax_gen_number (output, high, format);
226 /* Same as syntax_gen_pspp, below, but takes a va_list. */
228 syntax_gen_pspp_valist (struct string *output, const char *format,
233 size_t copy = strcspn (format, "%");
234 ds_put_substring (output, ss_buffer (format, copy));
239 assert (*format == '%');
245 const char *s = va_arg (args, char *);
249 syntax_gen_string (output, ss_cstr (s));
252 ds_put_cstr (output, s);
262 int i = va_arg (args, int);
263 ds_put_format (output, "%d", i);
269 double d = va_arg (args, double);
273 ds_put_format (output, "%f", d);
282 ds_put_char (output, '%');
291 /* printf-like function specialized for outputting PSPP syntax.
292 FORMAT is appended to OUTPUT. The following substitutions are
295 %sq: The char * argument is formatted as a PSPP string, as
296 if with a call to syntax_gen_string.
298 %ss: The char * argument is appended literally.
300 %d: Same as printf's %d.
302 %fp: The double argument is formatted precisely as a PSPP
303 number, as if with a call to syntax_gen_number with a
304 null FORMAT argument.
308 (These substitutions were chosen to allow GCC to check for
309 correct argument types.)
311 This function is somewhat experimental. If it proves useful,
312 the allowed substitutions will almost certainly be
315 syntax_gen_pspp (struct string *output, const char *format, ...)
318 va_start (args, format);
319 syntax_gen_pspp_valist (output, format, args);