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
39 int err_warning_count;
41 int err_already_flagged;
45 /* File locator stack. */
46 static const struct file_locator **file_loc;
47 static int nfile_loc, mfile_loc;
49 /* Fairly common public functions. */
51 /* Writes error message in CLASS, with title TITLE and text FORMAT,
52 formatted with printf, to the standard places. */
54 tmsg (int class, const char *title, const char *format, ...)
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 (int class, const char *format, ...)
77 err_location (&e.where);
80 va_start (args, format);
81 err_vmsg (&e, format, args);
85 /* Terminate due to fatal error in input. */
92 fprintf (stderr, "%s: %s\n", pgmname,
93 _("Terminating NOW due to a fatal error!"));
98 /* Terminate unless we're interactive or will go interactive when the
103 if (getl_reading_script)
105 if (getl_interactive)
112 /* File locator stack functions. */
114 /* Pushes F onto the stack of file locations. */
116 err_push_file_locator (const struct file_locator *f)
118 if (nfile_loc >= mfile_loc)
125 file_loc = xrealloc (file_loc, mfile_loc * sizeof *file_loc);
128 file_loc[nfile_loc++] = f;
131 /* Pops F off the stack of file locations.
132 Argument F is only used for verification that that is actually the
133 item on top of the stack. */
135 err_pop_file_locator (const struct file_locator *f)
137 assert (nfile_loc >= 0 && file_loc[nfile_loc - 1] == f);
141 /* Puts the current file and line number in F, or NULL and -1 if
144 err_location (struct file_locator *f)
147 *f = *file_loc[nfile_loc - 1];
149 getl_location (&f->filename, &f->line_number);
152 /* Obscure public functions. */
154 /* Writes a blank line to the error device(s).
155 FIXME: currently a no-op. */
161 /* Checks whether we've had so many errors that it's time to quit
162 processing this syntax file. If so, then take appropriate
165 err_check_count (void)
167 int error_class = getl_interactive ? MM : FE;
169 if (get_errorbreak() && err_error_count)
170 msg (error_class, _("Terminating execution of syntax file due to error."));
171 else if (err_error_count > get_mxerrs() )
172 msg (error_class, _("Errors (%d) exceeds limit (%d)."),
173 err_error_count, get_mxerrs());
174 else if (err_error_count + err_warning_count > get_mxwarns() )
175 msg (error_class, _("Warnings (%d) exceed limit (%d)."),
176 err_error_count + err_warning_count, get_mxwarns() );
183 /* Some machines are broken. Compensate. */
185 #define EXIT_SUCCESS 0
189 #define EXIT_FAILURE 1
192 static int terminating;
194 /* Halt-catch-fire. SUCCESS should be nonzero if exiting successfully
195 or zero if not. Despite the name, this is the usual way to finish,
196 successfully or not. */
198 err_hcf (int success)
203 getl_uninitialize ();
210 exit (success ? EXIT_SUCCESS : EXIT_FAILURE);
213 static void puts_stdout (const char *s);
214 static void dump_message (char *errbuf, unsigned indent,
215 void (*func) (const char *), unsigned width);
218 err_vmsg (const struct error *e, const char *format, va_list args)
223 ERR_IN_PROCEDURE = 01, /* 1=Display name of current procedure. */
224 ERR_WITH_FILE = 02, /* 1=Display filename and line number. */
227 /* Describes one class of error. */
230 int flags; /* Zero or more of ERR_*. */
231 int *count; /* Counting category. */
232 const char *banner; /* Banner. */
235 static const struct error_class error_classes[ERR_CLASS_COUNT] =
237 {0, NULL, N_("fatal")}, /* FE */
239 {3, &err_error_count, N_("error")}, /* SE */
240 {3, &err_warning_count, N_("warning")}, /* SW */
241 {3, NULL, N_("note")}, /* SM */
243 {0, NULL, N_("installation error")}, /* IE */
244 {2, NULL, N_("installation error")}, /* IS */
246 {2, &err_error_count, N_("error")}, /* DE */
247 {2, &err_warning_count, N_("warning")}, /* DW */
249 {0, &err_error_count, N_("error")}, /* ME */
250 {0, &err_warning_count, N_("warning")}, /* MW */
251 {0, NULL, N_("note")}, /* MM */
257 /* Check verbosity level. */
259 if (((class >> ERR_VERBOSITY_SHIFT) & ERR_VERBOSITY_MASK) > err_verbosity)
261 class &= ERR_CLASS_MASK;
263 assert (class >= 0 && class < ERR_CLASS_COUNT);
264 assert (format != NULL);
267 if (e->where.filename && (error_classes[class].flags & ERR_WITH_FILE))
269 ds_printf (&msg, "%s:", e->where.filename);
270 if (e->where.line_number != -1)
271 ds_printf (&msg, "%d:", e->where.line_number);
275 ds_printf (&msg, "%s: ", gettext (error_classes[class].banner));
278 int *count = error_classes[class].count;
283 if (cur_proc && (error_classes[class].flags & ERR_IN_PROCEDURE))
284 ds_printf (&msg, "%s: ", cur_proc);
287 ds_puts (&msg, e->title);
289 ds_vprintf (&msg, format, args);
291 /* FIXME: Check set_messages and set_errors to determine where to
292 send errors and messages.
294 Please note that this is not trivial. We have to avoid an
295 infinite loop in reporting errors that originate in the output
297 dump_message (ds_c_str (&msg), 8, puts_stdout, get_viewwidth());
301 if (e->class == FE && !terminating)
305 /* Private functions. */
308 /* Write S followed by a newline to stderr. */
310 puts_stderr (const char *s)
313 fputc ('\n', stderr);
317 /* Write S followed by a newline to stdout. */
319 puts_stdout (const char *s)
324 /* Returns 1 if the line must be broken here */
326 compulsory_break(int c)
328 return ( c == '\n' );
331 /* Returns 1 if C is a `break character', that is, if it is a good
332 place to break a message into lines. */
334 char_is_break (int quote, int c)
336 return ((quote && c == DIR_SEPARATOR)
337 || (!quote && (isspace (c) || c == '-' || c == '/')));
340 /* Returns 1 if C is a break character where the break should be made
341 BEFORE the character. */
343 break_before (int quote, int c)
345 return !quote && isspace (c);
348 /* If C is a break character, returns 1 if the break should be made
349 AFTER the character. Does not return a meaningful result if C is
350 not a break character. */
352 break_after (int quote, int c)
354 return !break_before (quote, c);
357 /* If you want very long words that occur at a bad break point to be
358 broken into two lines even if they're shorter than a whole line by
359 themselves, define as 2/3, or 4/5, or whatever fraction of a whole
360 line you think is necessary in order to consider a word long enough
361 to break into pieces. Otherwise, define as 0. See code to grok
362 the details. Do NOT parenthesize the expression! */
363 #define BREAK_LONG_WORD 0
364 /* #define BREAK_LONG_WORD 2/3 */
365 /* #define BREAK_LONG_WORD 4/5 */
367 /* Divides MSG into lines of WIDTH width for the first line and WIDTH
368 - INDENT width for each succeeding line. Each line is dumped
369 through FUNC, which may do with the string what it will. */
371 dump_message (char *msg, unsigned indent, void (*func) (const char *),
376 /* 1 when at a position inside double quotes ("). */
379 /* Buffer for a single line. */
382 /* If the message is short, just print the full thing. */
383 if (strlen (msg) < width)
389 /* Make sure the indent isn't too big relative to the page width. */
390 if (indent > width / 3)
393 buf = local_alloc (width + 2);
395 /* Advance WIDTH characters into MSG.
396 If that's a valid breakpoint, keep it; otherwise, back up.
398 for (cp = msg; (unsigned) (cp - msg) < width - 1 &&
399 ! compulsory_break(*cp); cp++)
403 if (break_after (quote, (unsigned char) *cp))
405 for (cp--; !char_is_break (quote, (unsigned char) *cp) && cp > msg; cp--)
409 if (break_after (quote, (unsigned char) *cp))
413 if (cp <= msg + width * BREAK_LONG_WORD)
414 for (; cp < msg + width - 1; cp++)
426 /* Repeat above procedure for remaining lines. */
429 static int hard_break=0;
434 /* Advance past whitespace. */
436 while ( isspace ((unsigned char) *cp) )
445 /* Advance WIDTH - INDENT characters. */
446 for (cp2 = cp; (unsigned) (cp2 - cp) < width - indent &&
447 *cp2 && !compulsory_break(*cp2); cp2++)
451 if ( compulsory_break(*cp2) )
457 /* Back up if this isn't a breakpoint. */
459 unsigned w = cp2 - cp;
460 if (*cp2 && ! compulsory_break(*cp2) )
461 for (cp2--; !char_is_break (quote, (unsigned char) *cp2) &&
470 if (w == width - indent
471 && (unsigned) (cp2 - cp) <= (width - indent) * BREAK_LONG_WORD)
472 for (; (unsigned) (cp2 - cp) < width - indent && *cp2 ; cp2++)
478 /* Write out the line. */
480 memset (buf, ' ', indent);
481 memcpy (&buf[indent], cp, cp2 - cp);
483 buf[indent + idx + cp2 - cp] = '\0';
493 request_bug_report_and_abort(const char *msg )
496 "******************************************************************\n"
497 "You have discovered a bug in PSPP.\n\n"
498 " Please report this, by sending "
499 "an email to " PACKAGE_BUGREPORT ",\n"
500 "explaining what you were doing when this happened, and including\n"
501 "a sample of your input file which caused it.\n");
504 "Also, please copy the following lines into your bug report:\n\n"
510 "default_config_path: %s\n"
512 "groff_font_path: %s\n"
514 "compiler version: %s\n"
534 fprintf(stderr,"Diagnosis: %s\n",msg);
537 "******************************************************************\n");
543 err_assert_fail(const char *expr, const char *file, int line)
546 snprintf(msg,256,"Assertion failed: %s:%d; (%s)",file,line,expr);
547 request_bug_report_and_abort( msg );