Previously, some errors were reported using the GNU "error" function from error.h
rather than the PSPP msg function. This wasn't too bad for the terminal user interace,
but gui users could miss important messages (since they never see stderr).
The reason for not using msg in some instances, was twofold: 1) Some
errors might occur before the messaging system had been initialised. 2) If an
error occured whilst reporting an error, an infinite loop would occur.
This change overcomes these problems by detecting re-entrancy, and uninitialised
messaging system, and falling back to fwrite if either of these conditions occur.
#include "libpspp/taint.h"
#include "libpspp/ext-array.h"
-#include "gl/error.h"
#include "gl/xalloc.h"
/* A temporary file that stores an array of cases. */
#include "libpspp/integer-format.h"
#include "libpspp/message.h"
-#include "gl/error.h"
#include "gl/minmax.h"
#include "gl/xalloc.h"
#include <config.h>
#include "libpspp/ext-array.h"
+#include "libpspp/message.h"
#include <errno.h>
#include <stdio.h>
#include "libpspp/cast.h"
#include "libpspp/temp-file.h"
-#include "gl/error.h"
#include "gl/unlocked-io.h"
#include "gl/xalloc.h"
struct ext_array *ea = xmalloc (sizeof *ea);
ea->file = create_temp_file ();
if (ea->file == NULL)
- error (0, errno, _("failed to create temporary file"));
+ msg_error (errno, _("failed to create temporary file"));
ea->position = 0;
ea->op = OP_WRITE;
return ea;
return true;
}
else
- error (0, errno, _("seeking in temporary file"));
+ msg_error (errno, _("seeking in temporary file"));
}
return false;
if (bytes > 0 && fread (buffer, bytes, 1, ea->file) != 1)
{
if (ferror (ea->file))
- error (0, errno, _("reading temporary file"));
+ msg_error (errno, _("reading temporary file"));
else if (feof (ea->file))
- error (0, 0, _("unexpected end of file reading temporary file"));
+ msg_error ( 0, _("unexpected end of file reading temporary file"));
else
NOT_REACHED ();
return false;
assert (!ext_array_error (ea));
if (bytes > 0 && fwrite (buffer, bytes, 1, ea->file) != 1)
{
- error (0, errno, _("writing to temporary file"));
+ msg_error (errno, _("writing to temporary file"));
return false;
}
ea->position += bytes;
#include "libpspp/assertion.h"
#include "libpspp/integer-format.h"
-#include "gl/error.h"
\f
/* Neutral intermediate representation for binary floating-point numbers. */
struct fp
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006, 2009, 2010,
+ 2011, 2013 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
/* Public functions. */
-/* Writes error message in CLASS, with text FORMAT, formatted with
- printf, to the standard places. */
+
void
-msg (enum msg_class class, const char *format, ...)
+vmsg (enum msg_class class, const char *format, va_list args)
{
struct msg m;
- va_list args;
m.category = msg_class_to_category (class);
m.severity = msg_class_to_severity (class);
- va_start (args, format);
m.text = xvasprintf (format, args);
m.file_name = NULL;
m.first_line = m.last_line = 0;
m.first_column = m.last_column = 0;
+
+ msg_emit (&m);
+}
+
+/* Writes error message in CLASS, with text FORMAT, formatted with
+ printf, to the standard places. */
+void
+msg (enum msg_class class, const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ vmsg (class, format, args);
+ va_end (args);
+}
+
+
+
+void
+msg_error (int errnum, const char *format, ...)
+{
+ va_list args;
+ char *e;
+ struct msg m;
+
+ m.category = MSG_C_GENERAL;
+ m.severity = MSG_S_ERROR;
+
+ va_start (args, format);
+ e = xvasprintf (format, args);
va_end (args);
+ m.file_name = NULL;
+ m.first_line = m.last_line = 0;
+ m.first_column = m.last_column = 0;
+ m.text = xasprintf (_("%s: %s"), e, strerror (errnum));
+ free (e);
+
msg_emit (&m);
}
+
+
void
msg_set_handler (void (*handler) (const struct msg *, void *aux), void *aux)
{
return counts[MSG_S_ERROR] > 0;
}
+
+static int entrances = 0;
+
+static void
+ship_message (struct msg *m)
+{
+ entrances++;
+ if ( ! m->shipped )
+ {
+ if (msg_handler && entrances <= 1)
+ msg_handler (m, msg_aux);
+ else
+ {
+ fwrite (m->text, 1, strlen (m->text), stderr);
+ fwrite ("\n", 1, 1, stderr);
+ }
+ }
+ m->shipped = true;
+ entrances--;
+}
+
static void
submit_note (char *s)
{
m.first_column = 0;
m.last_column = 0;
m.text = s;
- msg_handler (&m, msg_aux);
+ m.shipped = false;
+
+ ship_message (&m);
+
free (s);
}
static void
-process_msg (const struct msg *m)
+process_msg (struct msg *m)
{
int n_msgs, max_msgs;
-
if (too_many_errors
|| (too_many_notes && m->severity == MSG_S_NOTE)
|| (warnings_off && m->severity == MSG_S_WARNING) )
return;
- msg_handler (m, msg_aux);
+ ship_message (m);
counts[m->severity]++;
max_msgs = settings_get_max_messages (m->severity);
void
msg_emit (struct msg *m)
{
+ m->shipped = false;
if (!messages_disabled)
process_msg (m);
int first_column; /* 1-based first column, or 0 if none. */
int last_column; /* 1-based exclusive last column (0=none). */
char *text; /* Error text. */
+ bool shipped; /* True if this message has been emitted */
};
/* Initialization. */
PRINTF_FORMAT (2, 3);
void msg_emit (struct msg *);
+void msg_error (int errnum, const char *format, ...);
+
+
/* Enable and disable messages. */
void msg_enable (void);
void msg_disable (void);
#include <time.h>
#include "gl/crc.h"
-#include "gl/error.h"
#include "gl/fwriteerror.h"
#include "gl/xalloc.h"
+#include "libpspp/message.h"
+
#include "gettext.h"
#define _(msgid) gettext (msgid)
file = fopen (file_name, "wb");
if (file == NULL)
{
- error (0, errno, _("%s: error opening output file"), file_name);
+ msg_error (errno, _("%s: error opening output file"), file_name);
return NULL;
}
ok = true;
else
{
- error (0, errno, _("%s: write failed"), zw->file_name);
+ msg_error (errno, _("%s: write failed"), zw->file_name);
ok = false;
}
#include "output/table-item.h"
#include "output/text-item.h"
-#include "gl/error.h"
#include "gl/minmax.h"
#include "gl/xalloc.h"
if (dim >= 1 && errno != ERANGE && *tail == '\0')
dim = value;
else
- error (0, 0, _("%s: %s must be positive integer or `auto'"),
+ msg (MW, _("%s: %s must be positive integer or `auto'"),
option->driver_name, option->name);
}
}
if (a->width < MIN_WIDTH || a->length < MIN_LENGTH)
{
if (issue_error)
- error (0, 0,
+ msg (ME,
_("ascii: page excluding margins and headers "
"must be at least %d characters wide by %d lines long, but "
"as configured is only %d characters by %d lines"),
ascii_close_page (a);
if (fn_close (a->file_name, a->file) != 0)
- error (0, errno, _("ascii: closing output file `%s'"),
+ msg_error (ME, errno, _("ascii: closing output file `%s'"),
a->file_name);
a->file = NULL;
}
}
else
{
- error (0, errno, _("ascii: opening output file `%s'"),
+ msg_error (errno, _("ascii: opening output file `%s'"),
a->file_name);
a->error = true;
return false;
#include <cairo/cairo.h>
#include <pango/pango.h>
#include <pango/pangocairo.h>
-#include <errno.h>
#include <float.h>
#include <math.h>
#include <stdarg.h>
#include "output/cairo.h"
#include "output/chart-item.h"
-#include "gl/error.h"
#include "gl/xalloc.h"
#include "gl/xvasprintf.h"
#include <pango/pangocairo.h>
#include <stdlib.h>
-#include "gl/error.h"
#include "gl/intprops.h"
#include "gl/minmax.h"
#include "gl/xalloc.h"
desc = pango_font_description_from_string (string);
if (desc == NULL)
{
- error (0, 0, _("`%s': bad font specification"), string);
+ msg (MW, _("`%s': bad font specification"), string);
/* Fall back to DEFAULT_VALUE, which had better be a valid font
description. */
status = cairo_surface_status (surface);
if (status != CAIRO_STATUS_SUCCESS)
{
- error (0, 0, _("error opening output file `%s': %s"),
+ msg (ME, _("error opening output file `%s': %s"),
file_name, cairo_status_to_string (status));
cairo_surface_destroy (surface);
goto error;
if (xr->width / xr->char_width < MIN_WIDTH)
{
- error (0, 0, _("The defined page is not wide enough to hold at least %d "
+ msg (ME, _("The defined page is not wide enough to hold at least %d "
"characters in the default font. In fact, there's only "
"room for %d characters."),
MIN_WIDTH,
if (xr->length / xr->char_height < MIN_LENGTH)
{
- error (0, 0, _("The defined page is not long enough to hold at least %d "
+ msg (ME, _("The defined page is not long enough to hold at least %d "
"lines in the default font. In fact, there's only "
"room for %d lines."),
MIN_LENGTH,
cairo_surface_finish (cairo_get_target (xr->cairo));
status = cairo_status (xr->cairo);
if (status != CAIRO_STATUS_SUCCESS)
- error (0, 0, _("error drawing output for %s driver: %s"),
+ msg (ME, _("error drawing output for %s driver: %s"),
output_driver_get_name (driver),
cairo_status_to_string (status));
cairo_destroy (xr->cairo);
status = cairo_surface_write_to_png (surface, file_name);
if (status != CAIRO_STATUS_SUCCESS)
- error (0, 0, _("error writing output file `%s': %s"),
+ msg (ME, _("error writing output file `%s': %s"),
file_name, cairo_status_to_string (status));
cairo_destroy (cr);
#include "output/table-item.h"
#include "output/table-provider.h"
-#include "gl/error.h"
#include "gl/xalloc.h"
#include "gl/xvasprintf.h"
if (csv->file == NULL)
{
- error (0, errno, _("error opening output file `%s'"), csv->file_name);
+ msg_error (errno, _("error opening output file `%s'"), csv->file_name);
output_driver_destroy (d);
return NULL;
}
#include "output/output-item.h"
#include "output/text-item.h"
-#include "gl/error.h"
#include "gl/xalloc.h"
#include "gl/xmemdup0.h"
device_type = SETTINGS_DEVICE_LISTING;
else
{
- error (0, 0, _("%s is not a valid device type (the choices are `%s' and `%s')"),
+ msg (MW, _("%s is not a valid device type (the choices are `%s' and `%s')"),
device_string, "terminal", "listing");
device_type = default_device_type (file_name);
}
const char *key;
STRING_MAP_FOR_EACH_KEY (key, node, options)
- error (0, 0, _("%s: unknown option `%s'"), file_name, key);
+ msg (MW, _("%s: unknown option `%s'"), file_name, key);
}
string_map_clear (options);
#include "output/table-item.h"
#include "output/text-item.h"
-#include "error.h"
#include "xalloc.h"
#include "gettext.h"
html->file = fn_open (html->file_name, "w");
if (html->file == NULL)
{
- error (0, errno, _("error opening output file `%s'"), html->file_name);
+ msg_error (errno, _("error opening output file `%s'"), html->file_name);
goto error;
}
#include "data/file-name.h"
#include "libpspp/cast.h"
+#include "libpspp/message.h"
#include "libpspp/str.h"
#include "output/driver-provider.h"
#include "output/message-item.h"
#include "output/text-item.h"
-#include "gl/error.h"
#include "gl/fwriteerror.h"
#include "gl/xalloc.h"
if (journal != NULL && journal->file != NULL)
{
if (fwriteerror (journal->file))
- error (0, errno, _("error writing output file `%s'"),
+ msg_error (errno, _("error writing output file `%s'"),
journal_file_name);
journal->file = NULL;
}
j->file = fopen (journal_get_file_name (), "a");
if (j->file == NULL)
{
- error (0, errno, _("error opening output file `%s'"),
+ msg_error (errno, _("error opening output file `%s'"),
journal_get_file_name ());
output_driver_destroy (&j->driver);
return;
#include "libpspp/str.h"
#include "gl/c-strcase.h"
-#include "gl/error.h"
+#include "libpspp/message.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
return raw * factor;
syntax_error:
- error (0, 0, _("`%s' is not a valid length."), dimen);
+ msg (ME, _("`%s' is not a valid length."), dimen);
return -1;
}
/* Treat string that starts with digit as explicit size. */
ok = parse_paper_size (size, h, v);
if (!ok)
- error (0, 0, _("syntax error in paper size `%s'"), size);
+ msg (ME, _("syntax error in paper size `%s'"), size);
}
else
{
assert (ok);
return ok;
}
- error (0, 0, _("unknown paper type `%.*s'"),
+ msg (ME, _("unknown paper type `%.*s'"),
(int) ss_length (name), ss_data (name));
return false;
}
file = fopen (file_name, "r");
if (file == NULL)
{
- error (0, errno, _("error opening input file `%s'"), file_name);
+ msg_error (errno, _("error opening input file `%s'"), file_name);
return false;
}
if (!ds_read_config_line (&line, &line_number, file))
{
if (ferror (file))
- error (0, errno, _("error reading file `%s'"), file_name);
+ msg_error (errno, _("error reading file `%s'"), file_name);
break;
}
fclose (file);
ds_destroy (&line);
- error (0, 0, _("paper size file `%s' does not state a paper size"),
+ msg (ME, _("paper size file `%s' does not state a paper size"),
file_name);
return false;
}
#include "data/file-name.h"
#include "data/settings.h"
#include "libpspp/cast.h"
+#include "libpspp/message.h"
#include "output/driver-provider.h"
#include "output/message-item.h"
-#include "gl/error.h"
#include "gl/fwriteerror.h"
#include "gl/xalloc.h"
file = fn_open (file_name, "w");
if (file == NULL)
{
- error (0, errno, _("error opening output file `%s'"), file_name);
+ msg_error (errno, _("error opening output file `%s'"), file_name);
return NULL;
}
#include "libpspp/assertion.h"
#include "libpspp/cast.h"
+#include "libpspp/message.h"
#include "libpspp/str.h"
#include "libpspp/temp-file.h"
#include "libpspp/version.h"
#include "output/text-item.h"
#include "gl/xalloc.h"
-#include "gl/error.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
fp = create_temp_file ();
if (fp == NULL)
{
- error (0, errno, _("error creating temporary file"));
+ msg_error (errno, _("error creating temporary file"));
return false;
}
#include "output/driver-provider.h"
#include "output/measure.h"
-#include "gl/error.h"
#include "gl/xalloc.h"
#include "gettext.h"
return false;
else
{
- error (0, 0, _("%s: `%s' is `%s' but a Boolean value is required"),
+ msg (MW, _("%s: `%s' is `%s' but a Boolean value is required"),
driver_name, value, key);
return -1;
}
ds_put_format (&choices, "`%s'", s);
}
- error (0, 0, _("%s: `%s' is `%s' but one of the following "
+ msg (MW, _("%s: `%s' is `%s' but one of the following "
"is required: %s"),
o->driver_name, o->name, o->value, ds_cstr (&choices));
ds_destroy (&choices);
else if (max_value == INT_MAX)
{
if (min_value == 0)
- error (0, 0, _("%s: `%s' is `%s' but a nonnegative integer "
+ msg (MW, _("%s: `%s' is `%s' but a nonnegative integer "
"is required"),
o->driver_name, o->name, o->value);
else if (min_value == 1)
- error (0, 0, _("%s: `%s' is `%s' but a positive integer is "
+ msg (MW, _("%s: `%s' is `%s' but a positive integer is "
"required"), o->driver_name, o->name, o->value);
else if (min_value == INT_MIN)
- error (0, 0, _("%s: `%s' is `%s' but an integer is required"),
+ msg (MW, _("%s: `%s' is `%s' but an integer is required"),
o->driver_name, o->name, o->value);
else
- error (0, 0, _("%s: `%s' is `%s' but an integer greater "
+ msg (MW, _("%s: `%s' is `%s' but an integer greater "
"than %d is required"),
o->driver_name, o->name, o->value, min_value - 1);
}
else
- error (0, 0, _("%s: `%s' is `%s' but an integer between %d and "
+ msg (MW, _("%s: `%s' is `%s' but an integer between %d and "
"%d is required"),
o->driver_name, o->name, o->value, min_value, max_value);
}
chart_file_name = xstrdup (o->value);
else
{
- error (0, 0, _("%s: `%s' is `%s' but a file name that contains "
+ msg (MW, _("%s: `%s' is `%s' but a file name that contains "
"`#' is required."),
o->name, o->value, o->driver_name);
chart_file_name = default_chart_file_name (o->default_value);
#include "output/table-provider.h"
#include "output/text-item.h"
-#include "gl/error.h"
#include "gl/minmax.h"
#include "gl/xalloc.h"
#include "ui/gui/psppire-empty-list-store.h"
#include "ui/gui/psppire-var-sheet.h"
-#include "gl/error.h"
#include "gl/intprops.h"
#include "gl/xalloc.h"
#include "ui/gui/psppire-scanf.h"
#include "ui/syntax-gen.h"
-#include "gl/error.h"
#include "gl/intprops.h"
#include "gl/xalloc.h"
struct line_reader *reader = line_reader_for_file (file->encoding, file->file_name, O_RDONLY);
if (reader == NULL)
{
- msg (ME, _("Could not open `%s': %s"),
- file->file_name, strerror (errno));
+ msg_error (errno, _("Could not open `%s'"),
+ file->file_name);
return false;
}
#include "ui/gui/psppire-var-sheet.h"
#include "ui/gui/psppire-scanf.h"
-#include "gl/error.h"
#include "gl/intprops.h"
#include "gl/xalloc.h"
#include "ui/gui/psppire-var-sheet.h"
#include "ui/gui/psppire-scanf.h"
-#include "gl/error.h"
#include "gl/intprops.h"
#include "gl/xalloc.h"
#include "ui/gui/psppire-scanf.h"
#include "ui/syntax-gen.h"
-#include "gl/error.h"
#include "gl/intprops.h"
#include "gl/xalloc.h"
#include "ui/gui/psppire-scanf.h"
#include "ui/syntax-gen.h"
-#include "gl/error.h"
#include "gl/intprops.h"
#include "gl/xalloc.h"
#include <data/casereader.h>
-#include "gl/error.h"
#include "gl/intprops.h"
#include "gl/xalloc.h"
#include "ui/gui/builder-wrapper.h"
#include "ui/gui/psppire-output-window.h"
-#include "gl/error.h"
#include "gl/tmpdir.h"
#include "gl/xalloc.h"
#include "gl/c-xvasprintf.h"
if (path_search (dirname, sizeof dirname, NULL, NULL, true)
|| mkdtemp (dirname) == NULL)
{
- error (0, errno, _("failed to create temporary directory"));
+ msg_error (errno, _("failed to create temporary directory during clipboard operation"));
return;
}
filename = xasprintf ("%s/clip.tmp", dirname);
#include "ui/gui/psppire-scanf.h"
#include "ui/syntax-gen.h"
-#include "gl/error.h"
#include "gl/intprops.h"
#include "gl/xalloc.h"
tests_libpspp_sparse_xarray_test_SOURCES = \
tests/libpspp/sparse-xarray-test.c
tests_libpspp_sparse_xarray_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
-tests_libpspp_sparse_xarray_test_LDADD = src/libpspp/liblibpspp.la gl/libgl.la
+tests_libpspp_sparse_xarray_test_LDADD = src/libpspp/liblibpspp.la \
+ src/libpspp-core.la \
+ gl/libgl.la
tests_data_inexactify_SOURCES = tests/data/inexactify.c
check_PROGRAMS += tests/libpspp/zip-test
tests_libpspp_zip_test_SOURCES = \
tests/libpspp/zip-test.c
+
tests_libpspp_zip_test_CFLAGS = $(AM_CFLAGS)
tests_libpspp_zip_test_LDADD = \
src/libpspp/liblibpspp.la \
+ src/libpspp-core.la \
gl/libgl.la
-
check_PROGRAMS += tests/output/render-test
tests_output_render_test_SOURCES = tests/output/render-test.c
tests_output_render_test_LDADD = \
end data.
frequencies x/histogram.
])
- dnl PSPP will fail to create the output file. Currently this doesn't cause
- dnl PSPP's exit status to be nonzero, although this is arguably incorrect.
- dnl At any rate, PSPP should not crash.
- AT_CHECK([cd unwritable && pspp -o pspp.$1 ../unwritable.sps], [0],
+ dnl PSPP will fail to create the output file. Thus, the exit status is
+ dnl non zero
+ AT_CHECK([cd unwritable && pspp -o pspp.$1 ../unwritable.sps], [1],
[ignore], [ignore])
AT_CLEANUP])