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 #include "gl/ftoastr.h"
35 /* Appends to OUTPUT a pair of hex digits for each byte in IN. */
37 syntax_gen_hex_digits (struct string *output, struct substring in)
40 for (i = 0; i < in.length; i++)
42 unsigned char c = in.string[i];
43 ds_put_byte (output, "0123456789ABCDEF"[c >> 4]);
44 ds_put_byte (output, "0123456789ABCDEF"[c & 0xf]);
48 /* Returns true if IN contains any control characters, false
51 has_control_chars (struct substring in)
55 for (i = 0; i < in.length; i++)
56 if (iscntrl ((unsigned char) in.string[i]))
62 has_single_quote (struct substring str)
64 return (SIZE_MAX != ss_find_byte (str, '\''));
68 has_double_quote (struct substring str)
70 return (SIZE_MAX != ss_find_byte (str, '"'));
73 /* Appends to OUTPUT valid PSPP syntax for a quoted string that
76 IN must be encoded in UTF-8, and the quoted result will also
79 The string will be output as a regular quoted string unless it
80 contains control characters, in which case it is output as a
83 syntax_gen_string (struct string *output, struct substring in)
85 if (has_control_chars (in))
87 ds_put_cstr (output, "X'");
88 syntax_gen_hex_digits (output, in);
89 ds_put_byte (output, '\'');
96 /* This seemingly simple implementation is possible, because UTF-8
97 guarantees that bytes corresponding to basic characters (such as
98 '\'') cannot appear in a multi-byte character sequence except to
99 represent that basic character.
101 assert (is_basic ('\''));
103 quote = has_double_quote (in) && !has_single_quote (in) ? '\'' : '"';
104 ds_put_byte (output, quote);
105 for (i = 0; i < in.length; i++)
107 char c = in.string[i];
109 ds_put_byte (output, quote);
110 ds_put_byte (output, c);
112 ds_put_byte (output, quote);
116 /* Appends to OUTPUT a representation of NUMBER in PSPP syntax.
117 The representation is precise, that is, when PSPP parses the
118 representation, its value will be exactly NUMBER. (This might
119 not be the case on a C implementation where double has a
120 different representation.)
122 If NUMBER is the system-missing value, it is output as the
123 identifier SYSMIS. This may not be appropriate, because
124 SYSMIS is not consistently parsed throughout PSPP syntax as
125 the system-missing value. But in such circumstances the
126 system-missing value would not be meaningful anyhow, so the
127 caller should refrain from supplying the system-missing value
130 A value of LOWEST or HIGHEST is not treated specially.
132 If FORMAT is null, then the representation will be in numeric
133 form, e.g. 123 or 1.23e10.
135 If FORMAT is non-null, then it must point to a numeric format.
136 If the format is one easier for a user to understand when
137 expressed as a string than as a number (for example, a date
138 format), and the string representation precisely represents
139 NUMBER, then the string representation is written to OUTPUT.
140 Otherwise, NUMBER is output as if FORMAT was a null
143 syntax_gen_number (struct string *output,
144 double number, const struct fmt_spec *format)
146 assert (format == NULL || fmt_is_numeric (format->type));
149 & (FMT_CAT_DATE | FMT_CAT_TIME | FMT_CAT_DATE_COMPONENT)))
151 union value v_in, v_out;
156 s = data_out (&v_in, "FIXME", format);
158 /* FIXME: UTF8 encoded strings will fail here */
159 error = data_in (ss_cstr (s), LEGACY_NATIVE,
160 format->type, &v_out, 0, NULL);
164 if (ok && v_out.f == number)
166 syntax_gen_string (output, ss_cstr (s));
173 if (number == SYSMIS)
174 ds_put_cstr (output, "SYSMIS");
177 char s[DBL_BUFSIZE_BOUND];
179 dtoastr (s, sizeof s, 0, 0, number);
180 ds_put_cstr (output, s);
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);
198 char *s = CHAR_CAST_BUG (char *, value_str (value, width));
199 syntax_gen_string (output, ss_buffer (s, 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_byte (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);