+2008-03-04 Ben Pfaff <blp@gnu.org>
+
+ Patch #6427. Reviewed by John Darrington.
+
+ * automake.mk: Remove moved files.
+
+ * syntax-gen.c: Moved to src/ui (and rewritten).
+
+ * syntax-gen.h: Ditto.
+
2008-03-04 Ben Pfaff <blp@gnu.org>
Patch #6441. Reviewed by John Darrington.
src/libpspp/start-date.h \
src/libpspp/str.c \
src/libpspp/str.h \
- src/libpspp/syntax-gen.c \
- src/libpspp/syntax-gen.h \
src/libpspp/taint.c \
src/libpspp/taint.h \
src/libpspp/tower.c \
+++ /dev/null
-/* PSPP - a program for statistical analysis.
- Copyright (C) 2007 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-#include <libpspp/str.h>
-#include <libpspp/assertion.h>
-#include <string.h>
-#include <mbchar.h>
-
-#include "syntax-gen.h"
-
-
-static bool
-has_single_quote (const struct string *str)
-{
- return (SIZE_MAX != ds_find_char (str, '\''));
-}
-
-static bool
-has_double_quote (const struct string *str)
-{
- return (SIZE_MAX != ds_find_char (str, '"'));
-}
-
-/*
- Quotes the string STR. If STR contains no '\'' character, then
- the returned value will be enclosed in single quotes. Else, if STR
- contains no '"' character, then it will be enclosed in double
- quotes. Otherwise, it will be enclosed in single quotes, and each
- '\'' will be padded with another '\''.
-
- STR must be encoded in UTF-8, and the quoted result will also be
- encoded in UTF-8.
-*/
-void
-gen_quoted_string (struct string *str)
-{
- char c;
- static const char single_quote[] = "'";
- static const char double_quote[] = "\"";
-
- struct string quoted_str;
-
- bool pad_single_quotes = false;
- const char *delimiter ;
- char *s = ds_cstr (str);
-
- if ( has_double_quote (str))
- {
- delimiter = single_quote;
- if ( has_single_quote (str))
- pad_single_quotes = true;
- }
- else
- {
- delimiter = double_quote;
- }
-
- /* This seemingly simple implementation is possible, because UTF-8
- guarantees that bytes corresponding to basic characters (such as
- '\'') cannot appear in a multi-byte character sequence except to
- represent that basic character.
- */
- assert (is_basic ('\''));
-
- /* Initialise with the opening delimiter */
- ds_init_cstr ("ed_str, delimiter);
- while ((c = *s++))
- {
- ds_put_char ("ed_str, c);
-
- /* If c is a single quote, then append another one */
- if ( c == '\'' && pad_single_quotes)
- ds_put_char ("ed_str, c);
- }
-
- /* Add the closing delimiter */
- ds_put_cstr ("ed_str, delimiter);
-
- /* Copy the quoted string into str */
- ds_swap (str, "ed_str);
- ds_destroy ("ed_str);
-}
-
+++ /dev/null
-/* PSPP - a program for statistical analysis.
- Copyright (C) 2007 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#ifndef SYNTAX_GEN_H
-#define SYNTAX_GEN_H
-
-struct string;
-
-void gen_quoted_string (struct string *);
-
-#endif
+2008-03-04 Ben Pfaff <blp@gnu.org>
+
+ Patch #6427. Reviewed by John Darrington.
+
+ * automake.mk: Add new files.
+
+ * syntax-gen.c: New file. Based on former
+ src/libpspp/syntax-gen.c but rewritten.
+
+ * syntax-gen.h: New file. Based on former
+ src/libpspp/syntax-gen.h but rewritten.
+
2007-10-10 Ben Pfaff <blp@gnu.org>
* src/ui/debugger.c: Use debugger if HAVE_FORK is defined, not
src_ui_libuicommon_a_SOURCES = \
src/ui/debugger.c \
- src/ui/debugger.h
+ src/ui/debugger.h \
+ src/ui/syntax-gen.c \
+ src/ui/syntax-gen.h
+2008-03-04 Ben Pfaff <blp@gnu.org>
+
+ Patch #6427. Reviewed by John Darrington.
+
+ * comments-dialog.c: Adapt to new syntax generating code in
+ ui/syntax-gen.[ch].
+
+ * data-editor.c: Ditto.
+
+ * recode-dialog.c: Ditto.
+
+ * t-test-independent-samples-dialog.c: Ditto.
+
2008-02-29 John Darrington <john@darrington.wattle.id.au>
* psppire-data-editor.c psppire-data-editor.h: New files. Contains functionality
#include <language/syntax-string-source.h>
#include "syntax-editor.h"
#include "psppire-var-store.h"
-#include <libpspp/syntax-gen.h>
+#include <ui/syntax-gen.h>
#include "comments-dialog.h"
for (i = 0 ; i < gtk_text_buffer_get_line_count (buffer) ; ++i )
{
- struct string line;
- GtkTextIter start, end;
- gtk_text_buffer_get_iter_at_line (buffer, &start, i);
-
- end = start;
+ struct string tmp;
+ GtkTextIter start;
+ char *line;
- gtk_text_iter_forward_to_line_end (&end);
-
- if ( gtk_text_iter_ends_line (&start))
- ds_init_cstr (&line, "");
+ gtk_text_buffer_get_iter_at_line (buffer, &start, i);
+ if (gtk_text_iter_ends_line (&start))
+ line = g_strdup ("");
else
- ds_init_cstr (&line,
- gtk_text_buffer_get_text (buffer,
- &start, &end,
- FALSE));
+ {
+ GtkTextIter end = start;
+ gtk_text_iter_forward_to_line_end (&end);
+ line = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+ }
- gen_quoted_string (&line);
+ ds_init_empty (&tmp);
+ syntax_gen_string (&tmp, ss_cstr (line));
+ g_free (line);
- g_string_append_printf (str, " %s\n", ds_cstr (&line));
+ g_string_append_printf (str, " %s\n", ds_cstr (&tmp));
- ds_destroy (&line);
+ ds_destroy (&tmp);
}
g_string_append (str, " .\n");
#include "syntax-editor.h"
#include <language/syntax-string-source.h>
#include <language/command.h>
-#include <libpspp/syntax-gen.h>
+#include <ui/syntax-gen.h>
#include "window-manager.h"
#include "psppire-data-store.h"
g_assert (de->file_name);
- ds_init_cstr (&file_name, de->file_name);
- gen_quoted_string (&file_name);
+ ds_init_empty (&file_name);
+ syntax_gen_string (&file_name, ss_cstr (de->file_name));
if ( de->save_as_portable )
{
struct getl_interface *sss;
struct string filename;
- ds_init_cstr (&filename, file_name);
-
- gen_quoted_string (&filename);
+ ds_init_empty (&filename);
+ syntax_gen_string (&filename, ss_cstr (file_name));
sss = create_syntax_string_source ("GET FILE=%s.",
ds_cstr (&filename));
#include <ui/gui/psppire-dialog.h>
#include <ui/gui/psppire-var-store.h>
#include <ui/gui/syntax-editor.h>
-#include <libpspp/syntax-gen.h>
+#include <ui/syntax-gen.h>
#include "psppire-acr.h"
break;
case NV_STRING:
{
- struct string ds;
- ds_init_cstr (&ds, nv->v.s);
- gen_quoted_string (&ds);
+ struct string ds = DS_EMPTY_INITIALIZER;
+ syntax_gen_string (&ds, ss_cstr (nv->v.s));
g_string_append (str, ds_cstr (&ds));
ds_destroy (&ds);
}
break;
case OV_STRING:
{
- struct string ds;
- ds_init_cstr (&ds, ov->v.s);
- gen_quoted_string (&ds);
+ struct string ds = DS_EMPTY_INITIALIZER;
+ syntax_gen_string (&ds, ss_cstr (ov->v.s));
g_string_append (str, ds_cstr (&ds));
ds_destroy (&ds);
}
continue;
}
- ds_init_cstr (&ls, label);
+ ds_init_empty (&ls);
+ syntax_gen_string (&ls, ss_cstr (label));
g_free (label);
- gen_quoted_string (&ls);
g_string_append_printf (str, "\nVARIABLE LABELS %s %s.",
name, ds_cstr (&ls));
#include "dict-display.h"
#include "widget-io.h"
#include "t-test-options.h"
-#include <libpspp/syntax-gen.h>
+#include <ui/syntax-gen.h>
#include <language/syntax-string-source.h>
#include "syntax-editor.h"
if ( var_is_alpha (group_variable))
{
- struct string s;
- ds_init_cstr (&s, d->grps->val[0]);
- gen_quoted_string (&s);
+ struct string s = DS_EMPTY_INITIALIZER;
+ syntax_gen_string (&s, ss_cstr (d->grps->val[0]));
g_string_append (str, ds_cstr (&s));
ds_destroy (&s);
}
if ( var_is_alpha (group_variable))
{
- struct string s;
- ds_init_cstr (&s, d->grps->val[1]);
- gen_quoted_string (&s);
+ struct string s = DS_EMPTY_INITIALIZER;
+ syntax_gen_string (&s, ss_cstr (d->grps->val[1]));
g_string_append (str, ds_cstr (&s));
ds_destroy (&s);
}
--- /dev/null
+/* PSPPIRE - a graphical user interface for PSPP.
+ Copyright (C) 2008 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <ui/syntax-gen.h>
+
+#include <ctype.h>
+#include <mbchar.h>
+
+#include <data/data-in.h>
+#include <data/data-out.h>
+#include <data/format.h>
+#include <data/value.h>
+#include <libpspp/assertion.h>
+#include <libpspp/message.h>
+#include <libpspp/str.h>
+
+/* Appends to OUTPUT a pair of hex digits for each byte in IN. */
+static void
+syntax_gen_hex_digits (struct string *output, struct substring in)
+{
+ size_t i;
+ for (i = 0; i < in.length; i++)
+ {
+ unsigned char c = in.string[i];
+ ds_put_char (output, "0123456789ABCDEF"[c >> 4]);
+ ds_put_char (output, "0123456789ABCDEF"[c & 0xf]);
+ }
+}
+
+/* Returns true if IN contains any control characters, false
+ otherwise */
+static bool
+has_control_chars (struct substring in)
+{
+ size_t i;
+
+ for (i = 0; i < in.length; i++)
+ if (iscntrl ((unsigned char) in.string[i]))
+ return true;
+ return false;
+}
+
+static bool
+has_single_quote (struct substring str)
+{
+ return (SIZE_MAX != ss_find_char (str, '\''));
+}
+
+static bool
+has_double_quote (struct substring str)
+{
+ return (SIZE_MAX != ss_find_char (str, '"'));
+}
+
+/* Appends to OUTPUT valid PSPP syntax for a quoted string that
+ contains IN.
+
+ IN must be encoded in UTF-8, and the quoted result will also
+ be encoded in UTF-8.
+
+ The string will be output as a regular quoted string unless it
+ contains control characters, in which case it is output as a
+ hex string. */
+void
+syntax_gen_string (struct string *output, struct substring in)
+{
+ if (has_control_chars (in))
+ {
+ ds_put_cstr (output, "X'");
+ syntax_gen_hex_digits (output, in);
+ ds_put_char (output, '\'');
+ }
+ else
+ {
+ int quote;
+ size_t i;
+
+ /* This seemingly simple implementation is possible, because UTF-8
+ guarantees that bytes corresponding to basic characters (such as
+ '\'') cannot appear in a multi-byte character sequence except to
+ represent that basic character.
+ */
+ assert (is_basic ('\''));
+
+ quote = has_double_quote (in) && !has_single_quote (in) ? '\'' : '"';
+ ds_put_char (output, quote);
+ for (i = 0; i < in.length; i++)
+ {
+ char c = in.string[i];
+ if (c == quote)
+ ds_put_char (output, quote);
+ ds_put_char (output, c);
+ }
+ ds_put_char (output, quote);
+ }
+}
+
+/* Appends to OUTPUT a representation of NUMBER in PSPP syntax.
+ The representation is precise, that is, when PSPP parses the
+ representation, its value will be exactly NUMBER. (This might
+ not be the case on a C implementation where double has a
+ different representation.)
+
+ If NUMBER is the system-missing value, it is output as the
+ identifier SYSMIS. This may not be appropriate, because
+ SYSMIS is not consistently parsed throughout PSPP syntax as
+ the system-missing value. But in such circumstances the
+ system-missing value would not be meaningful anyhow, so the
+ caller should refrain from supplying the system-missing value
+ in such cases.
+
+ A value of LOWEST or HIGHEST is not treated specially.
+
+ If FORMAT is null, then the representation will be in numeric
+ form, e.g. 123 or 1.23e10.
+
+ If FORMAT is non-null, then it must point to a numeric format.
+ If the format is one easier for a user to understand when
+ expressed as a string than as a number (for example, a date
+ format), and the string representation precisely represents
+ NUMBER, then the string representation is written to OUTPUT.
+ Otherwise, NUMBER is output as if FORMAT was a null
+ pointer. */
+void
+syntax_gen_number (struct string *output,
+ double number, const struct fmt_spec *format)
+{
+ assert (format == NULL || fmt_is_numeric (format->type));
+ if (format != NULL
+ && (format->type
+ & (FMT_CAT_DATE | FMT_CAT_TIME | FMT_CAT_DATE_COMPONENT)))
+ {
+ union value v_in, v_out;
+ char buffer[FMT_MAX_NUMERIC_WIDTH];
+ bool ok;
+
+ v_in.f = number;
+ data_out (&v_in, format, buffer);
+ msg_disable ();
+ ok = data_in (ss_buffer (buffer, format->w), LEGACY_NATIVE,
+ format->type, false, 0, 0, &v_out, 0);
+ msg_enable ();
+ if (ok && v_out.f == number)
+ {
+ syntax_gen_string (output, ss_buffer (buffer, format->w));
+ return;
+ }
+ }
+
+ if (number == SYSMIS)
+ ds_put_cstr (output, "SYSMIS");
+ else
+ {
+ /* FIXME: This should consistently yield precisely the same
+ value as NUMBER on input, but its results for values
+ cannot be exactly represented in decimal are ugly: many
+ of them will have far more decimal digits than are
+ needed. The free-format floating point output routine
+ from Steele and White, "How to Print Floating-Point
+ Numbers Accurately" is really what we want. The MPFR
+ library has an implementation of this, or equivalent
+ functionality, in its mpfr_strtofr routine, but it would
+ not be nice to make PSPP depend on this. Probably, we
+ should implement something equivalent to it. */
+ ds_put_format (output, "%.*g", DBL_DIG + 1, number);
+ }
+}
+
+/* Appends to OUTPUT a representation of VALUE, which has the
+ specified WIDTH. If FORMAT is non-null, it influences the
+ output format. The representation is precise, that is, when
+ PSPP parses the representation, its value will be exactly
+ VALUE. */
+void
+syntax_gen_value (struct string *output, const union value *value, int width,
+ const struct fmt_spec *format)
+{
+ assert (format == NULL || fmt_var_width (format) == width);
+ if (width == 0)
+ syntax_gen_number (output, value->f, format);
+ else
+ syntax_gen_string (output, ss_buffer (value->s, width));
+}
+
+/* Appends <low> THRU <high> to OUTPUT. If LOW is LOWEST, then
+ it is formatted as the identifier LO; if HIGH is HIGHEST, then
+ it is formatted as the identifier HI. Otherwise, LOW and HIGH
+ are formatted as with a call to syntax_gen_num with the specified
+ FORMAT.
+
+ This is the opposite of the function parse_num_range. */
+void
+syntax_gen_num_range (struct string *output, double low, double high,
+ const struct fmt_spec *format)
+{
+ if (low == LOWEST)
+ ds_put_cstr (output, "LO");
+ else
+ syntax_gen_number (output, low, format);
+
+ ds_put_cstr (output, " THRU ");
+
+ if (high == HIGHEST)
+ ds_put_cstr (output, "HI");
+ else
+ syntax_gen_number (output, high, format);
+}
+
+/* Same as syntax_gen_pspp, below, but takes a va_list. */
+void
+syntax_gen_pspp_valist (struct string *output, const char *format,
+ va_list args)
+{
+ for (;;)
+ {
+ size_t copy = strcspn (format, "%");
+ ds_put_substring (output, ss_buffer (format, copy));
+ format += copy;
+
+ if (*format == '\0')
+ return;
+ assert (*format == '%');
+ format++;
+ switch (*format++)
+ {
+ case 's':
+ {
+ const char *s = va_arg (args, char *);
+ switch (*format++)
+ {
+ case 'q':
+ syntax_gen_string (output, ss_cstr (s));
+ break;
+ case 's':
+ ds_put_cstr (output, s);
+ break;
+ default:
+ NOT_REACHED ();
+ }
+ }
+ break;
+
+ case 'd':
+ {
+ int i = va_arg (args, int);
+ ds_put_format (output, "%d", i);
+ }
+ break;
+
+ case 'f':
+ {
+ double d = va_arg (args, double);
+ switch (*format++)
+ {
+ case 'p':
+ ds_put_format (output, "%f", d);
+ break;
+ default:
+ NOT_REACHED ();
+ }
+ break;
+ }
+
+ case '%':
+ ds_put_char (output, '%');
+ break;
+
+ default:
+ NOT_REACHED ();
+ }
+ }
+}
+
+/* printf-like function specialized for outputting PSPP syntax.
+ FORMAT is appended to OUTPUT. The following substitutions are
+ supported:
+
+ %sq: The char * argument is formatted as a PSPP string, as
+ if with a call to syntax_gen_string.
+
+ %ss: The char * argument is appended literally.
+
+ %d: Same as printf's %d.
+
+ %fp: The double argument is formatted precisely as a PSPP
+ number, as if with a call to syntax_gen_number with a
+ null FORMAT argument.
+
+ %%: Literal %.
+
+ (These substitutions were chosen to allow GCC to check for
+ correct argument types.)
+
+ This function is somewhat experimental. If it proves useful,
+ the allowed substitutions will almost certainly be
+ expanded. */
+void
+syntax_gen_pspp (struct string *output, const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ syntax_gen_pspp_valist (output, format, args);
+ va_end (args);
+}
--- /dev/null
+/* PSPPIRE - a graphical user interface for PSPP.
+ Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef SYNTAX_GEN_H
+#define SYNTAX_GEN_H 1
+
+/* These functions aid in composing PSPP syntax. */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <libpspp/compiler.h>
+
+struct fmt_spec;
+struct substring;
+struct string;
+union value;
+
+void syntax_gen_string (struct string *output, struct substring in);
+void syntax_gen_number (struct string *output,
+ double, const struct fmt_spec *format);
+void syntax_gen_value (struct string *output, const union value *value,
+ int width, const struct fmt_spec *format);
+void syntax_gen_num_range (struct string *output, double low, double high,
+ const struct fmt_spec *format);
+
+void syntax_gen_pspp_valist (struct string *output, const char *format,
+ va_list)
+ PRINTF_FORMAT (2, 0);
+void syntax_gen_pspp (struct string *output, const char *format, ...)
+ PRINTF_FORMAT (2, 3);
+
+#endif /* format-syntax.h */