1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 #include <libpspp/message.h>
26 #include <libpspp/alloc.h>
27 #include <data/filename.h>
28 #include <language/line-buffer.h>
29 #include <language/lexer/lexer.h>
30 #include <data/settings.h>
31 #include <ui/terminal/read-line.h>
32 #include <libpspp/version.h>
35 #define _(msgid) gettext (msgid)
36 #define N_(msgid) msgid
39 int err_warning_count;
41 int err_already_flagged;
45 static char *command_name;
47 /* Fairly common public functions. */
49 /* Writes error message in CLASS, with title TITLE and text FORMAT,
50 formatted with printf, to the standard places. */
52 tmsg (int class, const char *title, const char *format, ...)
58 err_location (&e.where);
61 va_start (args, format);
62 err_vmsg (&e, format, args);
66 /* Writes error message in CLASS, with text FORMAT, formatted with
67 printf, to the standard places. */
69 msg (int class, const char *format, ...)
75 err_location (&e.where);
78 va_start (args, format);
79 err_vmsg (&e, format, args);
83 /* Checks whether we've had so many errors that it's time to quit
84 processing this syntax file. */
86 err_check_count (void)
88 if (get_errorbreak() && err_error_count)
89 msg (MM, _("Terminating execution of syntax file due to error."));
90 else if (err_error_count > get_mxerrs() )
91 msg (MM, _("Errors (%d) exceeds limit (%d)."),
92 err_error_count, get_mxerrs());
93 else if (err_error_count + err_warning_count > get_mxwarns() )
94 msg (MM, _("Warnings (%d) exceed limit (%d)."),
95 err_error_count + err_warning_count, get_mxwarns() );
99 getl_abort_noninteractive ();
102 /* Some machines are broken. Compensate. */
104 #define EXIT_SUCCESS 0
108 #define EXIT_FAILURE 1
111 static void puts_stdout (const char *s);
112 static void dump_message (char *errbuf, unsigned indent,
113 void (*func) (const char *), unsigned width);
119 getl_uninitialize ();
120 readln_uninitialize();
124 err_vmsg (const struct error *e, const char *format, va_list args)
129 ERR_IN_PROCEDURE = 01, /* 1=Display name of current procedure. */
130 ERR_WITH_FILE = 02, /* 1=Display filename and line number. */
133 /* Describes one class of error. */
136 int flags; /* Zero or more of ERR_*. */
137 int *count; /* Counting category. */
138 const char *banner; /* Banner. */
141 static const struct error_class error_classes[ERR_CLASS_COUNT] =
143 {3, &err_error_count, N_("error")}, /* SE */
144 {3, &err_warning_count, N_("warning")}, /* SW */
145 {3, NULL, N_("note")}, /* SM */
147 {0, NULL, N_("installation error")}, /* IE */
148 {2, NULL, N_("installation error")}, /* IS */
150 {2, &err_error_count, N_("error")}, /* DE */
151 {2, &err_warning_count, N_("warning")}, /* DW */
153 {0, &err_error_count, N_("error")}, /* ME */
154 {0, &err_warning_count, N_("warning")}, /* MW */
155 {0, NULL, N_("note")}, /* MM */
161 /* Check verbosity level. */
163 if (((class >> ERR_VERBOSITY_SHIFT) & ERR_VERBOSITY_MASK) > err_verbosity)
165 class &= ERR_CLASS_MASK;
167 assert (class >= 0 && class < ERR_CLASS_COUNT);
168 assert (format != NULL);
171 if (e->where.filename && (error_classes[class].flags & ERR_WITH_FILE))
173 ds_printf (&msg, "%s:", e->where.filename);
174 if (e->where.line_number != -1)
175 ds_printf (&msg, "%d:", e->where.line_number);
179 ds_printf (&msg, "%s: ", gettext (error_classes[class].banner));
182 int *count = error_classes[class].count;
187 if (command_name != NULL && (error_classes[class].flags & ERR_IN_PROCEDURE))
188 ds_printf (&msg, "%s: ", command_name);
191 ds_puts (&msg, e->title);
193 ds_vprintf (&msg, format, args);
195 /* FIXME: Check set_messages and set_errors to determine where to
196 send errors and messages.
198 Please note that this is not trivial. We have to avoid an
199 infinite loop in reporting errors that originate in the output
201 dump_message (ds_c_str (&msg), 8, puts_stdout, get_viewwidth());
206 /* Private functions. */
209 /* Write S followed by a newline to stderr. */
211 puts_stderr (const char *s)
214 fputc ('\n', stderr);
218 /* Write S followed by a newline to stdout. */
220 puts_stdout (const char *s)
225 /* Returns 1 if the line must be broken here */
227 compulsory_break(int c)
229 return ( c == '\n' );
232 /* Returns 1 if C is a `break character', that is, if it is a good
233 place to break a message into lines. */
235 char_is_break (int quote, int c)
237 return ((quote && c == DIR_SEPARATOR)
238 || (!quote && (isspace (c) || c == '-' || c == '/')));
241 /* Returns 1 if C is a break character where the break should be made
242 BEFORE the character. */
244 break_before (int quote, int c)
246 return !quote && isspace (c);
249 /* If C is a break character, returns 1 if the break should be made
250 AFTER the character. Does not return a meaningful result if C is
251 not a break character. */
253 break_after (int quote, int c)
255 return !break_before (quote, c);
258 /* If you want very long words that occur at a bad break point to be
259 broken into two lines even if they're shorter than a whole line by
260 themselves, define as 2/3, or 4/5, or whatever fraction of a whole
261 line you think is necessary in order to consider a word long enough
262 to break into pieces. Otherwise, define as 0. See code to grok
263 the details. Do NOT parenthesize the expression! */
264 #define BREAK_LONG_WORD 0
265 /* #define BREAK_LONG_WORD 2/3 */
266 /* #define BREAK_LONG_WORD 4/5 */
268 /* Divides MSG into lines of WIDTH width for the first line and WIDTH
269 - INDENT width for each succeeding line. Each line is dumped
270 through FUNC, which may do with the string what it will. */
272 dump_message (char *msg, unsigned indent, void (*func) (const char *),
277 /* 1 when at a position inside double quotes ("). */
280 /* Buffer for a single line. */
283 /* If the message is short, just print the full thing. */
284 if (strlen (msg) < width)
290 /* Make sure the indent isn't too big relative to the page width. */
291 if (indent > width / 3)
294 buf = local_alloc (width + 2);
296 /* Advance WIDTH characters into MSG.
297 If that's a valid breakpoint, keep it; otherwise, back up.
299 for (cp = msg; (unsigned) (cp - msg) < width - 1 &&
300 ! compulsory_break(*cp); cp++)
304 if (break_after (quote, (unsigned char) *cp))
306 for (cp--; !char_is_break (quote, (unsigned char) *cp) && cp > msg; cp--)
310 if (break_after (quote, (unsigned char) *cp))
314 if (cp <= msg + width * BREAK_LONG_WORD)
315 for (; cp < msg + width - 1; cp++)
327 /* Repeat above procedure for remaining lines. */
330 static int hard_break=0;
335 /* Advance past whitespace. */
337 while ( isspace ((unsigned char) *cp) )
346 /* Advance WIDTH - INDENT characters. */
347 for (cp2 = cp; (unsigned) (cp2 - cp) < width - indent &&
348 *cp2 && !compulsory_break(*cp2); cp2++)
352 if ( compulsory_break(*cp2) )
358 /* Back up if this isn't a breakpoint. */
360 unsigned w = cp2 - cp;
361 if (*cp2 && ! compulsory_break(*cp2) )
362 for (cp2--; !char_is_break (quote, (unsigned char) *cp2) &&
371 if (w == width - indent
372 && (unsigned) (cp2 - cp) <= (width - indent) * BREAK_LONG_WORD)
373 for (; (unsigned) (cp2 - cp) < width - indent && *cp2 ; cp2++)
379 /* Write out the line. */
381 memset (buf, ' ', indent);
382 memcpy (&buf[indent], cp, cp2 - cp);
384 buf[indent + idx + cp2 - cp] = '\0';
392 /* Sets COMMAND_NAME as the command name included in some kinds
393 of error messages. */
395 err_set_command_name (const char *command_name_)
398 command_name = command_name_ ? xstrdup (command_name_) : NULL;
402 request_bug_report_and_abort(const char *msg )
405 "******************************************************************\n"
406 "You have discovered a bug in PSPP.\n\n"
407 " Please report this, by sending "
408 "an email to " PACKAGE_BUGREPORT ",\n"
409 "explaining what you were doing when this happened, and including\n"
410 "a sample of your input file which caused it.\n");
413 "Also, please copy the following lines into your bug report:\n\n"
419 "default_config_path: %s\n"
421 "groff_font_path: %s\n"
423 "compiler version: %s\n"
443 fprintf(stderr,"Diagnosis: %s\n",msg);
446 "******************************************************************\n");
452 err_assert_fail(const char *expr, const char *file, int line)
455 snprintf(msg,256,"Assertion failed: %s:%d; (%s)",file,line,expr);
456 request_bug_report_and_abort( msg );