1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2010, 2011 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/i18n.h"
31 #include "libpspp/message.h"
32 #include "libpspp/str.h"
33 #include "libpspp/misc.h"
35 #include "gl/ftoastr.h"
37 /* Appends to OUTPUT a pair of hex digits for each byte in IN. */
39 syntax_gen_hex_digits (struct string *output, struct substring in)
42 for (i = 0; i < in.length; i++)
44 unsigned char c = in.string[i];
45 ds_put_byte (output, "0123456789ABCDEF"[c >> 4]);
46 ds_put_byte (output, "0123456789ABCDEF"[c & 0xf]);
50 /* Returns true if IN contains any control characters, false
53 has_control_chars (struct substring in)
57 for (i = 0; i < in.length; i++)
58 if (iscntrl ((unsigned char) in.string[i]))
64 has_single_quote (struct substring str)
66 return (SIZE_MAX != ss_find_byte (str, '\''));
70 has_double_quote (struct substring str)
72 return (SIZE_MAX != ss_find_byte (str, '"'));
75 /* Appends to OUTPUT valid PSPP syntax for a quoted string that
78 IN must be encoded in UTF-8, and the quoted result will also
81 The string will be output as a regular quoted string unless it
82 contains control characters, in which case it is output as a
85 syntax_gen_string (struct string *output, struct substring in)
87 if (has_control_chars (in))
89 ds_put_cstr (output, "X'");
90 syntax_gen_hex_digits (output, in);
91 ds_put_byte (output, '\'');
98 /* This seemingly simple implementation is possible, because UTF-8
99 guarantees that bytes corresponding to basic characters (such as
100 '\'') cannot appear in a multi-byte character sequence except to
101 represent that basic character.
103 assert (is_basic ('\''));
105 quote = has_double_quote (in) && !has_single_quote (in) ? '\'' : '"';
106 ds_put_byte (output, quote);
107 for (i = 0; i < in.length; i++)
109 char c = in.string[i];
111 ds_put_byte (output, quote);
112 ds_put_byte (output, c);
114 ds_put_byte (output, quote);
118 /* Appends to OUTPUT a representation of NUMBER in PSPP syntax.
119 The representation is precise, that is, when PSPP parses the
120 representation, its value will be exactly NUMBER. (This might
121 not be the case on a C implementation where double has a
122 different representation.)
124 If NUMBER is the system-missing value, it is output as the
125 identifier SYSMIS. This may not be appropriate, because
126 SYSMIS is not consistently parsed throughout PSPP syntax as
127 the system-missing value. But in such circumstances the
128 system-missing value would not be meaningful anyhow, so the
129 caller should refrain from supplying the system-missing value
132 A value of LOWEST or HIGHEST is not treated specially.
134 If FORMAT is null, then the representation will be in numeric
135 form, e.g. 123 or 1.23e10.
137 If FORMAT is non-null, then it must point to a numeric format.
138 If the format is one easier for a user to understand when
139 expressed as a string than as a number (for example, a date
140 format), and the string representation precisely represents
141 NUMBER, then the string representation is written to OUTPUT.
142 Otherwise, NUMBER is output as if FORMAT was a null
145 syntax_gen_number (struct string *output,
146 double number, const struct fmt_spec *format)
148 assert (format == NULL || fmt_is_numeric (format->type));
151 & (FMT_CAT_DATE | FMT_CAT_TIME | FMT_CAT_DATE_COMPONENT)))
153 union value v_in, v_out;
158 s = data_out (&v_in, "FIXME", format);
160 /* FIXME: UTF8 encoded strings will fail here */
161 error = data_in (ss_cstr (s), C_ENCODING, format->type, &v_out, 0, NULL);
165 if (ok && v_out.f == number)
167 syntax_gen_string (output, ss_cstr (s));
174 if (number == SYSMIS)
175 ds_put_cstr (output, "SYSMIS");
178 char s[DBL_BUFSIZE_BOUND];
180 c_dtoastr (s, sizeof s, 0, 0, number);
181 ds_put_cstr (output, s);
185 /* Appends to OUTPUT a representation of VALUE, which has the
186 specified WIDTH. If FORMAT is non-null, it influences the
187 output format. The representation is precise, that is, when
188 PSPP parses the representation, its value will be exactly
191 syntax_gen_value (struct string *output, const union value *value, int width,
192 const struct fmt_spec *format)
194 assert (format == NULL || fmt_var_width (format) == width);
196 syntax_gen_number (output, value->f, format);
199 char *s = CHAR_CAST_BUG (char *, value_str (value, width));
200 syntax_gen_string (output, ss_buffer (s, width));
204 /* Appends <low> THRU <high> to OUTPUT. If LOW is LOWEST, then
205 it is formatted as the identifier LO; if HIGH is HIGHEST, then
206 it is formatted as the identifier HI. Otherwise, LOW and HIGH
207 are formatted as with a call to syntax_gen_num with the specified
210 This is the opposite of the function parse_num_range. */
212 syntax_gen_num_range (struct string *output, double low, double high,
213 const struct fmt_spec *format)
216 ds_put_cstr (output, "LO");
218 syntax_gen_number (output, low, format);
220 ds_put_cstr (output, " THRU ");
223 ds_put_cstr (output, "HI");
225 syntax_gen_number (output, high, format);
228 /* Same as syntax_gen_pspp, below, but takes a va_list. */
230 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 == '%');
246 directive = *format++;
247 if (directive == '.')
250 while (directive = *format++, c_isdigit (directive))
253 qualifier[x++] = directive;
255 qualifier[x++] = '\0';
256 precision = atoi (qualifier);
262 const char *s = va_arg (args, char *);
266 syntax_gen_string (output, ss_cstr (s));
269 ds_put_cstr (output, s);
279 int i = va_arg (args, int);
280 ds_put_format (output, "%d", i);
288 double d = va_arg (args, double);
295 strcat (conv, qualifier);
296 x += strlen (qualifier) + 1;
298 conv[x++] = directive;
301 ds_put_c_format (output, conv, d);
306 ds_put_byte (output, '%');
315 /* printf-like function specialized for outputting PSPP syntax.
316 FORMAT is appended to OUTPUT. The following substitutions are
319 %sq: The char * argument is formatted as a PSPP string, as
320 if with a call to syntax_gen_string.
322 %ss: The char * argument is appended literally.
324 %d: Same as printf's %d.
326 %f %g: Same as printf.
330 (These substitutions were chosen to allow GCC to check for
331 correct argument types.)
333 This function is somewhat experimental. If it proves useful,
334 the allowed substitutions will almost certainly be
337 syntax_gen_pspp (struct string *output, const char *format, ...)
340 va_start (args, format);
341 syntax_gen_pspp_valist (output, format, args);