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
41 #define _(msgid) gettext (msgid)
42 #define N_(msgid) msgid
45 int err_warning_count;
47 int err_already_flagged;
52 /* Fairly common public functions. */
54 /* Writes error message in CLASS, with title TITLE and text FORMAT,
55 formatted with printf, to the standard places. */
57 tmsg (int class, const char *title, const char *format, ...)
63 err_location (&e.where);
66 va_start (args, format);
67 err_vmsg (&e, format, args);
71 /* Writes error message in CLASS, with text FORMAT, formatted with
72 printf, to the standard places. */
74 msg (int class, const char *format, ...)
80 err_location (&e.where);
83 va_start (args, format);
84 err_vmsg (&e, format, args);
88 /* Terminate due to fatal error in input. */
95 fprintf (stderr, "%s: %s\n", program_name,
96 _("Terminating NOW due to a fatal error!"));
101 /* Terminate unless we're interactive or will go interactive when the
102 file is over with. */
106 if (getl_reading_script ())
108 if (getl_interactive)
115 /* Obscure public functions. */
117 /* Writes a blank line to the error device(s).
118 FIXME: currently a no-op. */
124 /* Checks whether we've had so many errors that it's time to quit
125 processing this syntax file. If so, then take appropriate
128 err_check_count (void)
130 int error_class = getl_interactive ? MM : FE;
132 if (get_errorbreak() && err_error_count)
133 msg (error_class, _("Terminating execution of syntax file due to error."));
134 else if (err_error_count > get_mxerrs() )
135 msg (error_class, _("Errors (%d) exceeds limit (%d)."),
136 err_error_count, get_mxerrs());
137 else if (err_error_count + err_warning_count > get_mxwarns() )
138 msg (error_class, _("Warnings (%d) exceed limit (%d)."),
139 err_error_count + err_warning_count, get_mxwarns() );
146 /* Some machines are broken. Compensate. */
148 #define EXIT_SUCCESS 0
152 #define EXIT_FAILURE 1
155 static void puts_stdout (const char *s);
156 static void dump_message (char *errbuf, unsigned indent,
157 void (*func) (const char *), unsigned width);
163 getl_uninitialize ();
164 readln_uninitialize();
168 err_vmsg (const struct error *e, const char *format, va_list args)
173 ERR_IN_PROCEDURE = 01, /* 1=Display name of current procedure. */
174 ERR_WITH_FILE = 02, /* 1=Display filename and line number. */
177 /* Describes one class of error. */
180 int flags; /* Zero or more of ERR_*. */
181 int *count; /* Counting category. */
182 const char *banner; /* Banner. */
185 static const struct error_class error_classes[ERR_CLASS_COUNT] =
187 {0, NULL, N_("fatal")}, /* FE */
189 {3, &err_error_count, N_("error")}, /* SE */
190 {3, &err_warning_count, N_("warning")}, /* SW */
191 {3, NULL, N_("note")}, /* SM */
193 {0, NULL, N_("installation error")}, /* IE */
194 {2, NULL, N_("installation error")}, /* IS */
196 {2, &err_error_count, N_("error")}, /* DE */
197 {2, &err_warning_count, N_("warning")}, /* DW */
199 {0, &err_error_count, N_("error")}, /* ME */
200 {0, &err_warning_count, N_("warning")}, /* MW */
201 {0, NULL, N_("note")}, /* MM */
207 /* Check verbosity level. */
209 if (((class >> ERR_VERBOSITY_SHIFT) & ERR_VERBOSITY_MASK) > err_verbosity)
211 class &= ERR_CLASS_MASK;
213 assert (class >= 0 && class < ERR_CLASS_COUNT);
214 assert (format != NULL);
217 if (e->where.filename && (error_classes[class].flags & ERR_WITH_FILE))
219 ds_printf (&msg, "%s:", e->where.filename);
220 if (e->where.line_number != -1)
221 ds_printf (&msg, "%d:", e->where.line_number);
225 ds_printf (&msg, "%s: ", gettext (error_classes[class].banner));
228 int *count = error_classes[class].count;
233 if (cur_proc && (error_classes[class].flags & ERR_IN_PROCEDURE))
234 ds_printf (&msg, "%s: ", cur_proc);
237 ds_puts (&msg, e->title);
239 ds_vprintf (&msg, format, args);
241 /* FIXME: Check set_messages and set_errors to determine where to
242 send errors and messages.
244 Please note that this is not trivial. We have to avoid an
245 infinite loop in reporting errors that originate in the output
247 dump_message (ds_c_str (&msg), 8, puts_stdout, get_viewwidth());
255 /* Private functions. */
258 /* Write S followed by a newline to stderr. */
260 puts_stderr (const char *s)
263 fputc ('\n', stderr);
267 /* Write S followed by a newline to stdout. */
269 puts_stdout (const char *s)
274 /* Returns 1 if the line must be broken here */
276 compulsory_break(int c)
278 return ( c == '\n' );
281 /* Returns 1 if C is a `break character', that is, if it is a good
282 place to break a message into lines. */
284 char_is_break (int quote, int c)
286 return ((quote && c == DIR_SEPARATOR)
287 || (!quote && (isspace (c) || c == '-' || c == '/')));
290 /* Returns 1 if C is a break character where the break should be made
291 BEFORE the character. */
293 break_before (int quote, int c)
295 return !quote && isspace (c);
298 /* If C is a break character, returns 1 if the break should be made
299 AFTER the character. Does not return a meaningful result if C is
300 not a break character. */
302 break_after (int quote, int c)
304 return !break_before (quote, c);
307 /* If you want very long words that occur at a bad break point to be
308 broken into two lines even if they're shorter than a whole line by
309 themselves, define as 2/3, or 4/5, or whatever fraction of a whole
310 line you think is necessary in order to consider a word long enough
311 to break into pieces. Otherwise, define as 0. See code to grok
312 the details. Do NOT parenthesize the expression! */
313 #define BREAK_LONG_WORD 0
314 /* #define BREAK_LONG_WORD 2/3 */
315 /* #define BREAK_LONG_WORD 4/5 */
317 /* Divides MSG into lines of WIDTH width for the first line and WIDTH
318 - INDENT width for each succeeding line. Each line is dumped
319 through FUNC, which may do with the string what it will. */
321 dump_message (char *msg, unsigned indent, void (*func) (const char *),
326 /* 1 when at a position inside double quotes ("). */
329 /* Buffer for a single line. */
332 /* If the message is short, just print the full thing. */
333 if (strlen (msg) < width)
339 /* Make sure the indent isn't too big relative to the page width. */
340 if (indent > width / 3)
343 buf = local_alloc (width + 2);
345 /* Advance WIDTH characters into MSG.
346 If that's a valid breakpoint, keep it; otherwise, back up.
348 for (cp = msg; (unsigned) (cp - msg) < width - 1 &&
349 ! compulsory_break(*cp); cp++)
353 if (break_after (quote, (unsigned char) *cp))
355 for (cp--; !char_is_break (quote, (unsigned char) *cp) && cp > msg; cp--)
359 if (break_after (quote, (unsigned char) *cp))
363 if (cp <= msg + width * BREAK_LONG_WORD)
364 for (; cp < msg + width - 1; cp++)
376 /* Repeat above procedure for remaining lines. */
379 static int hard_break=0;
384 /* Advance past whitespace. */
386 while ( isspace ((unsigned char) *cp) )
395 /* Advance WIDTH - INDENT characters. */
396 for (cp2 = cp; (unsigned) (cp2 - cp) < width - indent &&
397 *cp2 && !compulsory_break(*cp2); cp2++)
401 if ( compulsory_break(*cp2) )
407 /* Back up if this isn't a breakpoint. */
409 unsigned w = cp2 - cp;
410 if (*cp2 && ! compulsory_break(*cp2) )
411 for (cp2--; !char_is_break (quote, (unsigned char) *cp2) &&
420 if (w == width - indent
421 && (unsigned) (cp2 - cp) <= (width - indent) * BREAK_LONG_WORD)
422 for (; (unsigned) (cp2 - cp) < width - indent && *cp2 ; cp2++)
428 /* Write out the line. */
430 memset (buf, ' ', indent);
431 memcpy (&buf[indent], cp, cp2 - cp);
433 buf[indent + idx + cp2 - cp] = '\0';
443 request_bug_report_and_abort(const char *msg )
446 "******************************************************************\n"
447 "You have discovered a bug in PSPP.\n\n"
448 " Please report this, by sending "
449 "an email to " PACKAGE_BUGREPORT ",\n"
450 "explaining what you were doing when this happened, and including\n"
451 "a sample of your input file which caused it.\n");
454 "Also, please copy the following lines into your bug report:\n\n"
460 "default_config_path: %s\n"
462 "groff_font_path: %s\n"
464 "compiler version: %s\n"
484 fprintf(stderr,"Diagnosis: %s\n",msg);
487 "******************************************************************\n");
493 err_assert_fail(const char *expr, const char *file, int line)
496 snprintf(msg,256,"Assertion failed: %s:%d; (%s)",file,line,expr);
497 request_bug_report_and_abort( msg );