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>
36 #define _(msgid) gettext (msgid)
37 #define N_(msgid) msgid
40 int err_warning_count;
42 int err_already_flagged;
46 static char *command_name;
48 /* Fairly common public functions. */
50 /* Writes error message in CLASS, with title TITLE and text FORMAT,
51 formatted with printf, to the standard places. */
53 tmsg (int class, const char *title, const char *format, ...)
59 err_location (&e.where);
62 va_start (args, format);
63 err_vmsg (&e, format, args);
67 /* Writes error message in CLASS, with text FORMAT, formatted with
68 printf, to the standard places. */
70 msg (int class, const char *format, ...)
76 err_location (&e.where);
79 va_start (args, format);
80 err_vmsg (&e, format, args);
84 /* Writes MESSAGE formatted with printf, to stderr, if the
85 verbosity level is at least LEVEL. */
87 verbose_msg (int level, const char *format, ...)
89 if (err_verbosity >= level)
93 va_start (args, format);
94 fprintf (stderr, "%s: ", program_name);
95 vfprintf (stderr, format, args);
101 /* Checks whether we've had so many errors that it's time to quit
102 processing this syntax file. */
104 err_check_count (void)
106 if (get_errorbreak() && err_error_count)
107 msg (MM, _("Terminating execution of syntax file due to error."));
108 else if (err_error_count > get_mxerrs() )
109 msg (MM, _("Errors (%d) exceeds limit (%d)."),
110 err_error_count, get_mxerrs());
111 else if (err_error_count + err_warning_count > get_mxwarns() )
112 msg (MM, _("Warnings (%d) exceed limit (%d)."),
113 err_error_count + err_warning_count, get_mxwarns() );
117 getl_abort_noninteractive ();
120 /* Some machines are broken. Compensate. */
122 #define EXIT_SUCCESS 0
126 #define EXIT_FAILURE 1
129 static void puts_stdout (const char *s);
130 static void dump_message (char *errbuf, unsigned indent,
131 void (*func) (const char *), unsigned width);
137 getl_uninitialize ();
138 readln_uninitialize();
142 err_vmsg (const struct error *e, const char *format, va_list args)
147 ERR_IN_PROCEDURE = 01, /* 1=Display name of current procedure. */
148 ERR_WITH_FILE = 02, /* 1=Display filename and line number. */
151 /* Describes one class of error. */
154 int flags; /* Zero or more of ERR_*. */
155 int *count; /* Counting category. */
156 const char *banner; /* Banner. */
159 static const struct error_class error_classes[MSG_CLASS_CNT] =
161 {3, &err_error_count, N_("error")}, /* SE */
162 {3, &err_warning_count, N_("warning")}, /* SW */
163 {3, NULL, N_("note")}, /* SM */
165 {2, &err_error_count, N_("error")}, /* DE */
166 {2, &err_warning_count, N_("warning")}, /* DW */
168 {0, &err_error_count, N_("error")}, /* ME */
169 {0, &err_warning_count, N_("warning")}, /* MW */
170 {0, NULL, N_("note")}, /* MM */
175 assert (e->class >= 0 && e->class < MSG_CLASS_CNT);
176 assert (format != NULL);
179 if (e->where.filename && (error_classes[e->class].flags & ERR_WITH_FILE))
181 ds_printf (&msg, "%s:", e->where.filename);
182 if (e->where.line_number != -1)
183 ds_printf (&msg, "%d:", e->where.line_number);
187 ds_printf (&msg, "%s: ", gettext (error_classes[e->class].banner));
190 int *count = error_classes[e->class].count;
195 if (command_name != NULL
196 && (error_classes[e->class].flags & ERR_IN_PROCEDURE))
197 ds_printf (&msg, "%s: ", command_name);
200 ds_puts (&msg, e->title);
202 ds_vprintf (&msg, format, args);
204 /* FIXME: Check set_messages and set_errors to determine where to
205 send errors and messages.
207 Please note that this is not trivial. We have to avoid an
208 infinite loop in reporting errors that originate in the output
210 dump_message (ds_c_str (&msg), 8, puts_stdout, get_viewwidth());
215 /* Private functions. */
218 /* Write S followed by a newline to stderr. */
220 puts_stderr (const char *s)
223 fputc ('\n', stderr);
227 /* Write S followed by a newline to stdout. */
229 puts_stdout (const char *s)
234 /* Returns 1 if the line must be broken here */
236 compulsory_break(int c)
238 return ( c == '\n' );
241 /* Returns 1 if C is a `break character', that is, if it is a good
242 place to break a message into lines. */
244 char_is_break (int quote, int c)
246 return ((quote && c == DIR_SEPARATOR)
247 || (!quote && (isspace (c) || c == '-' || c == '/')));
250 /* Returns 1 if C is a break character where the break should be made
251 BEFORE the character. */
253 break_before (int quote, int c)
255 return !quote && isspace (c);
258 /* If C is a break character, returns 1 if the break should be made
259 AFTER the character. Does not return a meaningful result if C is
260 not a break character. */
262 break_after (int quote, int c)
264 return !break_before (quote, c);
267 /* If you want very long words that occur at a bad break point to be
268 broken into two lines even if they're shorter than a whole line by
269 themselves, define as 2/3, or 4/5, or whatever fraction of a whole
270 line you think is necessary in order to consider a word long enough
271 to break into pieces. Otherwise, define as 0. See code to grok
272 the details. Do NOT parenthesize the expression! */
273 #define BREAK_LONG_WORD 0
274 /* #define BREAK_LONG_WORD 2/3 */
275 /* #define BREAK_LONG_WORD 4/5 */
277 /* Divides MSG into lines of WIDTH width for the first line and WIDTH
278 - INDENT width for each succeeding line. Each line is dumped
279 through FUNC, which may do with the string what it will. */
281 dump_message (char *msg, unsigned indent, void (*func) (const char *),
286 /* 1 when at a position inside double quotes ("). */
289 /* Buffer for a single line. */
292 /* If the message is short, just print the full thing. */
293 if (strlen (msg) < width)
299 /* Make sure the indent isn't too big relative to the page width. */
300 if (indent > width / 3)
303 buf = local_alloc (width + 2);
305 /* Advance WIDTH characters into MSG.
306 If that's a valid breakpoint, keep it; otherwise, back up.
308 for (cp = msg; (unsigned) (cp - msg) < width - 1 &&
309 ! compulsory_break(*cp); cp++)
313 if (break_after (quote, (unsigned char) *cp))
315 for (cp--; !char_is_break (quote, (unsigned char) *cp) && cp > msg; cp--)
319 if (break_after (quote, (unsigned char) *cp))
323 if (cp <= msg + width * BREAK_LONG_WORD)
324 for (; cp < msg + width - 1; cp++)
336 /* Repeat above procedure for remaining lines. */
339 static int hard_break=0;
344 /* Advance past whitespace. */
346 while ( isspace ((unsigned char) *cp) )
355 /* Advance WIDTH - INDENT characters. */
356 for (cp2 = cp; (unsigned) (cp2 - cp) < width - indent &&
357 *cp2 && !compulsory_break(*cp2); cp2++)
361 if ( compulsory_break(*cp2) )
367 /* Back up if this isn't a breakpoint. */
369 unsigned w = cp2 - cp;
370 if (*cp2 && ! compulsory_break(*cp2) )
371 for (cp2--; !char_is_break (quote, (unsigned char) *cp2) &&
380 if (w == width - indent
381 && (unsigned) (cp2 - cp) <= (width - indent) * BREAK_LONG_WORD)
382 for (; (unsigned) (cp2 - cp) < width - indent && *cp2 ; cp2++)
388 /* Write out the line. */
390 memset (buf, ' ', indent);
391 memcpy (&buf[indent], cp, cp2 - cp);
393 buf[indent + idx + cp2 - cp] = '\0';
401 /* Sets COMMAND_NAME as the command name included in some kinds
402 of error messages. */
404 err_set_command_name (const char *command_name_)
407 command_name = command_name_ ? xstrdup (command_name_) : NULL;
411 request_bug_report_and_abort(const char *msg )
414 "******************************************************************\n"
415 "You have discovered a bug in PSPP.\n\n"
416 " Please report this, by sending "
417 "an email to " PACKAGE_BUGREPORT ",\n"
418 "explaining what you were doing when this happened, and including\n"
419 "a sample of your input file which caused it.\n");
422 "Also, please copy the following lines into your bug report:\n\n"
428 "default_config_path: %s\n"
430 "groff_font_path: %s\n"
432 "compiler version: %s\n"
452 fprintf(stderr,"Diagnosis: %s\n",msg);
455 "******************************************************************\n");
461 err_assert_fail(const char *expr, const char *file, int line)
464 snprintf(msg,256,"Assertion failed: %s:%d; (%s)",file,line,expr);
465 request_bug_report_and_abort( msg );