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/file-name.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 /* Public functions. */
50 /* Writes error message in CLASS, with title TITLE and text FORMAT,
51 formatted with printf, to the standard places. */
53 tmsg (enum msg_class class, const char *title, const char *format, ...)
58 e.category = msg_class_to_category (class);
59 e.severity = msg_class_to_severity (class);
60 err_location (&e.where);
63 va_start (args, format);
64 err_vmsg (&e, format, args);
68 /* Writes error message in CLASS, with text FORMAT, formatted with
69 printf, to the standard places. */
71 msg (enum msg_class class, const char *format, ...)
76 e.category = msg_class_to_category (class);
77 e.severity = msg_class_to_severity (class);
78 err_location (&e.where);
81 va_start (args, format);
82 err_vmsg (&e, format, args);
86 /* Writes MESSAGE formatted with printf, to stderr, if the
87 verbosity level is at least LEVEL. */
89 verbose_msg (int level, const char *format, ...)
91 if (err_verbosity >= level)
95 va_start (args, format);
96 fprintf (stderr, "%s: ", program_name);
97 vfprintf (stderr, format, args);
103 /* Checks whether we've had so many errors that it's time to quit
104 processing this syntax file. */
106 err_check_count (void)
108 if (get_errorbreak() && err_error_count)
109 msg (MN, _("Terminating execution of syntax file due to error."));
110 else if (err_error_count > get_mxerrs() )
111 msg (MN, _("Errors (%d) exceeds limit (%d)."),
112 err_error_count, get_mxerrs());
113 else if (err_error_count + err_warning_count > get_mxwarns() )
114 msg (MN, _("Warnings (%d) exceed limit (%d)."),
115 err_error_count + err_warning_count, get_mxwarns() );
119 getl_abort_noninteractive ();
122 /* Some machines are broken. Compensate. */
124 #define EXIT_SUCCESS 0
128 #define EXIT_FAILURE 1
131 static void puts_stdout (const char *s);
132 static void dump_message (char *errbuf, unsigned indent,
133 void (*func) (const char *), unsigned width);
139 getl_uninitialize ();
140 readln_uninitialize();
144 err_vmsg (const struct error *e, const char *format, va_list args)
148 bool show_command_name; /* Show command name with error? */
149 bool show_file_location; /* Show syntax file location? */
152 static const struct category categories[] =
154 {false, false}, /* MSG_GENERAL. */
155 {true, true}, /* MSG_SYNTAX. */
156 {false, true}, /* MSG_DATA. */
161 const char *name; /* How to identify this severity. */
162 int *count; /* Number of msgs with this severity so far. */
165 static struct severity severities[] =
167 {N_("error"), &err_error_count}, /* MSG_ERROR. */
168 {N_("warning"), &err_warning_count}, /* MSG_WARNING. */
169 {NULL, NULL}, /* MSG_NOTE. */
172 const struct category *category = &categories[e->category];
173 const struct severity *severity = &severities[e->severity];
174 struct string msg = DS_INITIALIZER;
176 if (category->show_file_location && e->where.file_name)
178 ds_printf (&msg, "%s:", e->where.file_name);
179 if (e->where.line_number != -1)
180 ds_printf (&msg, "%d:", e->where.line_number);
184 if (severity->name != NULL)
185 ds_printf (&msg, "%s: ", gettext (severity->name));
187 if (severity->count != NULL)
190 if (category->show_command_name && command_name != NULL)
191 ds_printf (&msg, "%s: ", command_name);
194 ds_puts (&msg, e->title);
196 ds_vprintf (&msg, format, args);
198 /* FIXME: Check set_messages and set_errors to determine where to
199 send errors and messages. */
200 dump_message (ds_c_str (&msg), 8, puts_stdout, get_viewwidth());
205 /* Private functions. */
207 /* Write S followed by a newline to stdout. */
209 puts_stdout (const char *s)
214 /* Returns 1 if the line must be broken here */
216 compulsory_break(int c)
218 return ( c == '\n' );
221 /* Returns 1 if C is a `break character', that is, if it is a good
222 place to break a message into lines. */
224 char_is_break (int quote, int c)
226 return ((quote && c == '/')
227 || (!quote && (isspace (c) || c == '-' || c == '/')));
230 /* Returns 1 if C is a break character where the break should be made
231 BEFORE the character. */
233 break_before (int quote, int c)
235 return !quote && isspace (c);
238 /* If C is a break character, returns 1 if the break should be made
239 AFTER the character. Does not return a meaningful result if C is
240 not a break character. */
242 break_after (int quote, int c)
244 return !break_before (quote, c);
247 /* If you want very long words that occur at a bad break point to be
248 broken into two lines even if they're shorter than a whole line by
249 themselves, define as 2/3, or 4/5, or whatever fraction of a whole
250 line you think is necessary in order to consider a word long enough
251 to break into pieces. Otherwise, define as 0. See code to grok
252 the details. Do NOT parenthesize the expression! */
253 #define BREAK_LONG_WORD 0
254 /* #define BREAK_LONG_WORD 2/3 */
255 /* #define BREAK_LONG_WORD 4/5 */
257 /* Divides MSG into lines of WIDTH width for the first line and WIDTH
258 - INDENT width for each succeeding line. Each line is dumped
259 through FUNC, which may do with the string what it will. */
261 dump_message (char *msg, unsigned indent, void (*func) (const char *),
266 /* 1 when at a position inside double quotes ("). */
269 /* Buffer for a single line. */
272 /* If the message is short, just print the full thing. */
273 if (strlen (msg) < width)
279 /* Make sure the indent isn't too big relative to the page width. */
280 if (indent > width / 3)
283 buf = local_alloc (width + 2);
285 /* Advance WIDTH characters into MSG.
286 If that's a valid breakpoint, keep it; otherwise, back up.
288 for (cp = msg; (unsigned) (cp - msg) < width - 1 &&
289 ! compulsory_break(*cp); cp++)
293 if (break_after (quote, (unsigned char) *cp))
295 for (cp--; !char_is_break (quote, (unsigned char) *cp) && cp > msg; cp--)
299 if (break_after (quote, (unsigned char) *cp))
303 if (cp <= msg + width * BREAK_LONG_WORD)
304 for (; cp < msg + width - 1; cp++)
316 /* Repeat above procedure for remaining lines. */
319 static int hard_break=0;
324 /* Advance past whitespace. */
326 while ( isspace ((unsigned char) *cp) )
335 /* Advance WIDTH - INDENT characters. */
336 for (cp2 = cp; (unsigned) (cp2 - cp) < width - indent &&
337 *cp2 && !compulsory_break(*cp2); cp2++)
341 if ( compulsory_break(*cp2) )
347 /* Back up if this isn't a breakpoint. */
349 unsigned w = cp2 - cp;
350 if (*cp2 && ! compulsory_break(*cp2) )
351 for (cp2--; !char_is_break (quote, (unsigned char) *cp2) &&
360 if (w == width - indent
361 && (unsigned) (cp2 - cp) <= (width - indent) * BREAK_LONG_WORD)
362 for (; (unsigned) (cp2 - cp) < width - indent && *cp2 ; cp2++)
368 /* Write out the line. */
370 memset (buf, ' ', indent);
371 memcpy (&buf[indent], cp, cp2 - cp);
373 buf[indent + idx + cp2 - cp] = '\0';
381 /* Sets COMMAND_NAME as the command name included in some kinds
382 of error messages. */
384 err_set_command_name (const char *command_name_)
387 command_name = command_name_ ? xstrdup (command_name_) : NULL;
391 request_bug_report_and_abort(const char *msg )
394 "******************************************************************\n"
395 "You have discovered a bug in PSPP.\n\n"
396 " Please report this, by sending "
397 "an email to " PACKAGE_BUGREPORT ",\n"
398 "explaining what you were doing when this happened, and including\n"
399 "a sample of your input file which caused it.\n");
402 "Also, please copy the following lines into your bug report:\n\n"
408 "default_config_path: %s\n"
410 "groff_font_path: %s\n"
412 "compiler version: %s\n"
432 fprintf(stderr,"Diagnosis: %s\n",msg);
435 "******************************************************************\n");
441 err_assert_fail(const char *expr, const char *file, int line)
444 snprintf(msg,256,"Assertion failed: %s:%d; (%s)",file,line,expr);
445 request_bug_report_and_abort( msg );