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., 59 Temple Place - Suite 330, Boston, MA
37 int err_warning_count;
39 int err_already_flagged;
43 /* File locator stack. */
44 static const struct file_locator **file_loc;
45 static int nfile_loc, mfile_loc;
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, ...)
56 /* Format the message into BUF. */
60 va_start (args, format);
61 vsnprintf (buf, 1024, format, args);
65 /* Output the message. */
70 err_location (&e.where);
77 /* Writes error message in CLASS, with text FORMAT, formatted with
78 printf, to the standard places. */
80 msg (int class, const char *format, ...)
86 /* Format the message into BUF. */
90 va_start (args, format);
91 ds_vprintf (&buf, format, args);
95 /* Output the message. */
100 err_location (&e.where);
109 /* Terminate due to fatal error in input. */
116 fprintf (stderr, "%s: %s\n", pgmname,
117 _("Terminating NOW due to a fatal error!"));
122 /* Terminate unless we're interactive or will go interactive when the
123 file is over with. */
127 if (getl_reading_script)
129 if (getl_interactive)
136 /* File locator stack functions. */
138 /* Pushes F onto the stack of file locations. */
140 err_push_file_locator (const struct file_locator *f)
142 if (nfile_loc >= mfile_loc)
149 file_loc = xrealloc (file_loc, mfile_loc * sizeof *file_loc);
152 file_loc[nfile_loc++] = f;
155 /* Pops F off the stack of file locations.
156 Argument F is only used for verification that that is actually the
157 item on top of the stack. */
159 err_pop_file_locator (const struct file_locator *f)
161 assert (nfile_loc >= 0 && file_loc[nfile_loc - 1] == f);
165 /* Puts the current file and line number in F, or NULL and -1 if
168 err_location (struct file_locator *f)
171 *f = *file_loc[nfile_loc - 1];
173 getl_location (&f->filename, &f->line_number);
176 /* Obscure public functions. */
178 /* Writes a blank line to the error device(s).
179 FIXME: currently a no-op. */
185 /* Checks whether we've had so many errors that it's time to quit
186 processing this syntax file. If so, then take appropriate
189 err_check_count (void)
191 int error_class = getl_interactive ? MM : FE;
193 if (get_errorbreak() && err_error_count)
194 msg (error_class, _("Terminating execution of syntax file due to error."));
195 else if (err_error_count > get_mxerrs() )
196 msg (error_class, _("Errors (%d) exceeds limit (%d)."),
197 err_error_count, get_mxerrs());
198 else if (err_error_count + err_warning_count > get_mxwarns() )
199 msg (error_class, _("Warnings (%d) exceed limit (%d)."),
200 err_error_count + err_warning_count, get_mxwarns() );
207 /* Some machines are broken. Compensate. */
209 #define EXIT_SUCCESS 0
213 #define EXIT_FAILURE 1
216 static int terminating;
218 /* Halt-catch-fire. SUCCESS should be nonzero if exiting successfully
219 or zero if not. Despite the name, this is the usual way to finish,
220 successfully or not. */
222 err_hcf (int success)
227 getl_uninitialize ();
234 exit (success ? EXIT_SUCCESS : EXIT_FAILURE);
237 static void puts_stdout (const char *s);
238 static void dump_message (char *errbuf, unsigned indent,
239 void (*func) (const char *), unsigned width);
242 err_vmsg (const struct error *e)
247 ERR_IN_PROCEDURE = 01, /* 1=Display name of current procedure. */
248 ERR_WITH_FILE = 02, /* 1=Display filename and line number. */
251 /* Describes one class of error. */
254 int flags; /* Zero or more of ERR_*. */
255 int *count; /* Counting category. */
256 const char *banner; /* Banner. */
259 static const struct error_class error_classes[ERR_CLASS_COUNT] =
261 {0, NULL, N_("fatal")}, /* FE */
263 {3, &err_error_count, N_("error")}, /* SE */
264 {3, &err_warning_count, N_("warning")}, /* SW */
265 {3, NULL, N_("note")}, /* SM */
267 {0, NULL, N_("installation error")}, /* IE */
268 {2, NULL, N_("installation error")}, /* IS */
270 {2, &err_error_count, N_("error")}, /* DE */
271 {2, &err_warning_count, N_("warning")}, /* DW */
273 {0, &err_error_count, N_("error")}, /* ME */
274 {0, &err_warning_count, N_("warning")}, /* MW */
275 {0, NULL, N_("note")}, /* MM */
281 /* Check verbosity level. */
283 if (((class >> ERR_VERBOSITY_SHIFT) & ERR_VERBOSITY_MASK) > err_verbosity)
285 class &= ERR_CLASS_MASK;
287 assert (class >= 0 && class < ERR_CLASS_COUNT);
288 assert (e->text != NULL);
291 if (e->where.filename && (error_classes[class].flags & ERR_WITH_FILE))
293 ds_printf (&msg, "%s:", e->where.filename);
294 if (e->where.line_number != -1)
295 ds_printf (&msg, "%d:", e->where.line_number);
299 ds_printf (&msg, "%s: ", gettext (error_classes[class].banner));
302 int *count = error_classes[class].count;
307 if (cur_proc && (error_classes[class].flags & ERR_IN_PROCEDURE))
308 ds_printf (&msg, "%s: ", cur_proc);
311 ds_puts (&msg, e->title);
313 ds_puts (&msg, e->text);
315 /* FIXME: Check set_messages and set_errors to determine where to
316 send errors and messages.
318 Please note that this is not trivial. We have to avoid an
319 infinite loop in reporting errors that originate in the output
321 dump_message (ds_c_str (&msg), 8, puts_stdout, get_viewwidth());
325 if (e->class == FE && !terminating)
329 /* Private functions. */
332 /* Write S followed by a newline to stderr. */
334 puts_stderr (const char *s)
337 fputc ('\n', stderr);
341 /* Write S followed by a newline to stdout. */
343 puts_stdout (const char *s)
348 /* Returns 1 if the line must be broken here */
350 compulsory_break(int c)
352 return ( c == '\n' );
355 /* Returns 1 if C is a `break character', that is, if it is a good
356 place to break a message into lines. */
358 char_is_break (int quote, int c)
360 return ((quote && c == DIR_SEPARATOR)
361 || (!quote && (isspace (c) || c == '-' || c == '/')));
364 /* Returns 1 if C is a break character where the break should be made
365 BEFORE the character. */
367 break_before (int quote, int c)
369 return !quote && isspace (c);
372 /* If C is a break character, returns 1 if the break should be made
373 AFTER the character. Does not return a meaningful result if C is
374 not a break character. */
376 break_after (int quote, int c)
378 return !break_before (quote, c);
381 /* If you want very long words that occur at a bad break point to be
382 broken into two lines even if they're shorter than a whole line by
383 themselves, define as 2/3, or 4/5, or whatever fraction of a whole
384 line you think is necessary in order to consider a word long enough
385 to break into pieces. Otherwise, define as 0. See code to grok
386 the details. Do NOT parenthesize the expression! */
387 #define BREAK_LONG_WORD 0
388 /* #define BREAK_LONG_WORD 2/3 */
389 /* #define BREAK_LONG_WORD 4/5 */
391 /* Divides MSG into lines of WIDTH width for the first line and WIDTH
392 - INDENT width for each succeeding line. Each line is dumped
393 through FUNC, which may do with the string what it will. */
395 dump_message (char *msg, unsigned indent, void (*func) (const char *),
400 /* 1 when at a position inside double quotes ("). */
403 /* Buffer for a single line. */
406 /* If the message is short, just print the full thing. */
407 if (strlen (msg) < width)
413 /* Make sure the indent isn't too big relative to the page width. */
414 if (indent > width / 3)
417 buf = local_alloc (width + 2);
419 /* Advance WIDTH characters into MSG.
420 If that's a valid breakpoint, keep it; otherwise, back up.
422 for (cp = msg; (unsigned) (cp - msg) < width - 1 &&
423 ! compulsory_break(*cp); cp++)
427 if (break_after (quote, (unsigned char) *cp))
429 for (cp--; !char_is_break (quote, (unsigned char) *cp) && cp > msg; cp--)
433 if (break_after (quote, (unsigned char) *cp))
437 if (cp <= msg + width * BREAK_LONG_WORD)
438 for (; cp < msg + width - 1; cp++)
450 /* Repeat above procedure for remaining lines. */
453 static int hard_break=0;
458 /* Advance past whitespace. */
460 while ( isspace ((unsigned char) *cp) )
469 /* Advance WIDTH - INDENT characters. */
470 for (cp2 = cp; (unsigned) (cp2 - cp) < width - indent &&
471 *cp2 && !compulsory_break(*cp2); cp2++)
475 if ( compulsory_break(*cp2) )
481 /* Back up if this isn't a breakpoint. */
483 unsigned w = cp2 - cp;
484 if (*cp2 && ! compulsory_break(*cp2) )
485 for (cp2--; !char_is_break (quote, (unsigned char) *cp2) &&
494 if (w == width - indent
495 && (unsigned) (cp2 - cp) <= (width - indent) * BREAK_LONG_WORD)
496 for (; (unsigned) (cp2 - cp) < width - indent && *cp2 ; cp2++)
502 /* Write out the line. */
504 memset (buf, ' ', indent);
505 memcpy (&buf[indent], cp, cp2 - cp);
509 buf[indent + idx + cp2 - cp] = '\n';
512 buf[indent + idx + cp2 - cp] = '\0';
522 request_bug_report_and_abort(const char *msg )
525 "******************************************************************\n"
526 "You have discovered a bug in PSPP.\n\n"
527 " Please report this, by sending "
528 "an email to " PACKAGE_BUGREPORT ",\n"
529 "explaining what you were doing when this happened, and including\n"
530 "a sample of your input file which caused it.\n");
533 "Also, please copy the following lines into your bug report:\n\n"
539 "default_config_path: %s\n"
541 "groff_font_path: %s\n"
555 fprintf(stderr,"Diagnosis: %s\n",msg);
558 "******************************************************************\n");
564 err_assert_fail(const char *expr, const char *file, int line)
567 snprintf(msg,256,"Assertion failed: %s:%d; (%s)",file,line,expr);
568 request_bug_report_and_abort( msg );