1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2010, 2011, 2014 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/c-ctype.h"
36 #include "gl/ftoastr.h"
38 /* Appends to OUTPUT a pair of hex digits for each byte in IN. */
40 syntax_gen_hex_digits (struct string
*output
, struct substring in
)
43 for (i
= 0; i
< in
.length
; i
++)
45 unsigned char c
= in
.string
[i
];
46 ds_put_byte (output
, "0123456789ABCDEF"[c
>> 4]);
47 ds_put_byte (output
, "0123456789ABCDEF"[c
& 0xf]);
51 /* Returns true if IN contains any control characters, false
54 has_control_chars (struct substring in
)
58 for (i
= 0; i
< in
.length
; i
++)
59 if (iscntrl ((unsigned char) in
.string
[i
]))
65 has_single_quote (struct substring str
)
67 return (SIZE_MAX
!= ss_find_byte (str
, '\''));
71 has_double_quote (struct substring str
)
73 return (SIZE_MAX
!= ss_find_byte (str
, '"'));
76 /* Appends to OUTPUT valid PSPP syntax for a quoted string that
79 IN must be encoded in UTF-8, and the quoted result will also
82 The string will be output as a regular quoted string unless it
83 contains control characters, in which case it is output as a
86 syntax_gen_string (struct string
*output
, struct substring in
)
88 if (has_control_chars (in
))
90 ds_put_cstr (output
, "X'");
91 syntax_gen_hex_digits (output
, in
);
92 ds_put_byte (output
, '\'');
99 /* This seemingly simple implementation is possible, because UTF-8
100 guarantees that bytes corresponding to basic characters (such as
101 '\'') cannot appear in a multi-byte character sequence except to
102 represent that basic character.
104 assert (is_basic ('\''));
106 quote
= has_double_quote (in
) && !has_single_quote (in
) ? '\'' : '"';
107 ds_put_byte (output
, quote
);
108 for (i
= 0; i
< in
.length
; i
++)
110 char c
= in
.string
[i
];
112 ds_put_byte (output
, quote
);
113 ds_put_byte (output
, c
);
115 ds_put_byte (output
, quote
);
119 /* Appends to OUTPUT a representation of NUMBER in PSPP syntax.
120 The representation is precise, that is, when PSPP parses the
121 representation, its value will be exactly NUMBER. (This might
122 not be the case on a C implementation where double has a
123 different representation.)
125 If NUMBER is the system-missing value, it is output as the
126 identifier SYSMIS. This may not be appropriate, because
127 SYSMIS is not consistently parsed throughout PSPP syntax as
128 the system-missing value. But in such circumstances the
129 system-missing value would not be meaningful anyhow, so the
130 caller should refrain from supplying the system-missing value
133 A value of LOWEST or HIGHEST is not treated specially.
135 If FORMAT is null, then the representation will be in numeric
136 form, e.g. 123 or 1.23e10.
138 If FORMAT is non-null, then it must point to a numeric format.
139 If the format is one easier for a user to understand when
140 expressed as a string than as a number (for example, a date
141 format), and the string representation precisely represents
142 NUMBER, then the string representation is written to OUTPUT.
143 Otherwise, NUMBER is output as if FORMAT was a null
146 syntax_gen_number (struct string
*output
,
147 double number
, const struct fmt_spec
*format
)
149 assert (format
== NULL
|| fmt_is_numeric (format
->type
));
152 & (FMT_CAT_DATE
| FMT_CAT_TIME
| FMT_CAT_DATE_COMPONENT
)))
154 union value v_in
, v_out
;
159 s
= data_out (&v_in
, "FIXME", format
);
161 /* FIXME: UTF8 encoded strings will fail here */
162 error
= data_in (ss_cstr (s
), C_ENCODING
, format
->type
, &v_out
, 0, NULL
);
166 if (ok
&& v_out
.f
== number
)
168 syntax_gen_string (output
, ss_cstr (s
));
175 if (number
== SYSMIS
)
176 ds_put_cstr (output
, "SYSMIS");
179 char s
[DBL_BUFSIZE_BOUND
];
181 c_dtoastr (s
, sizeof s
, 0, 0, number
);
182 ds_put_cstr (output
, s
);
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
);
200 char *s
= CHAR_CAST_BUG (char *, value_str (value
, width
));
201 syntax_gen_string (output
, ss_buffer (s
, width
));
205 /* Appends <low> THRU <high> to OUTPUT. If LOW is LOWEST, then
206 it is formatted as the identifier LO; if HIGH is HIGHEST, then
207 it is formatted as the identifier HI. Otherwise, LOW and HIGH
208 are formatted as with a call to syntax_gen_num with the specified
211 This is the opposite of the function parse_num_range. */
213 syntax_gen_num_range (struct string
*output
, double low
, double high
,
214 const struct fmt_spec
*format
)
217 ds_put_cstr (output
, "LO");
219 syntax_gen_number (output
, low
, format
);
221 ds_put_cstr (output
, " THRU ");
224 ds_put_cstr (output
, "HI");
226 syntax_gen_number (output
, high
, format
);
229 /* Same as syntax_gen_pspp, below, but takes a va_list. */
231 syntax_gen_pspp_valist (struct string
*output
, const char *format
,
239 size_t copy
= strcspn (format
, "%");
240 ds_put_substring (output
, ss_buffer (format
, copy
));
245 assert (*format
== '%');
247 directive
= *format
++;
248 if (directive
== '.')
251 while (directive
= *format
++, c_isdigit (directive
))
254 qualifier
[x
++] = directive
;
256 qualifier
[x
++] = '\0';
257 precision
= atoi (qualifier
);
263 const char *s
= va_arg (args
, char *);
267 syntax_gen_string (output
, ss_cstr (s
));
270 ds_put_cstr (output
, s
);
280 int i
= va_arg (args
, int);
281 ds_put_format (output
, "%d", i
);
289 double d
= va_arg (args
, double);
296 strcat (conv
, qualifier
);
297 x
+= strlen (qualifier
) + 1;
299 conv
[x
++] = directive
;
302 ds_put_c_format (output
, conv
, d
);
307 ds_put_byte (output
, '%');
316 /* printf-like function specialized for outputting PSPP syntax.
317 FORMAT is appended to OUTPUT. The following substitutions are
320 %sq: The char * argument is formatted as a PSPP string, as
321 if with a call to syntax_gen_string.
323 %ss: The char * argument is appended literally.
325 %d: Same as printf's %d.
327 %f %g: Same as printf.
331 (These substitutions were chosen to allow GCC to check for
332 correct argument types.)
334 This function is somewhat experimental. If it proves useful,
335 the allowed substitutions will almost certainly be
338 syntax_gen_pspp (struct string
*output
, const char *format
, ...)
341 va_start (args
, format
);
342 syntax_gen_pspp_valist (output
, format
, args
);