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
40 #define _(msgid) gettext (msgid)
41 #define N_(msgid) msgid
44 int err_warning_count;
46 int err_already_flagged;
50 /* File locator stack. */
51 static const struct file_locator **file_loc;
52 static int nfile_loc, mfile_loc;
54 /* Fairly common public functions. */
56 /* Writes error message in CLASS, with title TITLE and text FORMAT,
57 formatted with printf, to the standard places. */
59 tmsg (int class, const char *title, const char *format, ...)
65 err_location (&e.where);
68 va_start (args, format);
69 err_vmsg (&e, format, args);
73 /* Writes error message in CLASS, with text FORMAT, formatted with
74 printf, to the standard places. */
76 msg (int class, const char *format, ...)
82 err_location (&e.where);
85 va_start (args, format);
86 err_vmsg (&e, format, args);
90 /* Terminate due to fatal error in input. */
97 fprintf (stderr, "%s: %s\n", program_name,
98 _("Terminating NOW due to a fatal error!"));
103 /* Terminate unless we're interactive or will go interactive when the
104 file is over with. */
108 if (getl_reading_script)
110 if (getl_interactive)
117 /* File locator stack functions. */
119 /* Pushes F onto the stack of file locations. */
121 err_push_file_locator (const struct file_locator *f)
123 if (nfile_loc >= mfile_loc)
130 file_loc = xnrealloc (file_loc, mfile_loc, sizeof *file_loc);
133 file_loc[nfile_loc++] = f;
136 /* Pops F off the stack of file locations.
137 Argument F is only used for verification that that is actually the
138 item on top of the stack. */
140 err_pop_file_locator (const struct file_locator *f)
142 assert (nfile_loc >= 0 && file_loc[nfile_loc - 1] == f);
146 /* Puts the current file and line number in F, or NULL and -1 if
149 err_location (struct file_locator *f)
152 *f = *file_loc[nfile_loc - 1];
154 getl_location (&f->filename, &f->line_number);
157 /* Obscure public functions. */
159 /* Writes a blank line to the error device(s).
160 FIXME: currently a no-op. */
166 /* Checks whether we've had so many errors that it's time to quit
167 processing this syntax file. If so, then take appropriate
170 err_check_count (void)
172 int error_class = getl_interactive ? MM : FE;
174 if (get_errorbreak() && err_error_count)
175 msg (error_class, _("Terminating execution of syntax file due to error."));
176 else if (err_error_count > get_mxerrs() )
177 msg (error_class, _("Errors (%d) exceeds limit (%d)."),
178 err_error_count, get_mxerrs());
179 else if (err_error_count + err_warning_count > get_mxwarns() )
180 msg (error_class, _("Warnings (%d) exceed limit (%d)."),
181 err_error_count + err_warning_count, get_mxwarns() );
188 /* Some machines are broken. Compensate. */
190 #define EXIT_SUCCESS 0
194 #define EXIT_FAILURE 1
197 static void puts_stdout (const char *s);
198 static void dump_message (char *errbuf, unsigned indent,
199 void (*func) (const char *), unsigned width);
205 getl_uninitialize ();
206 readln_uninitialize();
210 nfile_loc = mfile_loc = 0;
214 err_vmsg (const struct error *e, const char *format, va_list args)
219 ERR_IN_PROCEDURE = 01, /* 1=Display name of current procedure. */
220 ERR_WITH_FILE = 02, /* 1=Display filename and line number. */
223 /* Describes one class of error. */
226 int flags; /* Zero or more of ERR_*. */
227 int *count; /* Counting category. */
228 const char *banner; /* Banner. */
231 static const struct error_class error_classes[ERR_CLASS_COUNT] =
233 {0, NULL, N_("fatal")}, /* FE */
235 {3, &err_error_count, N_("error")}, /* SE */
236 {3, &err_warning_count, N_("warning")}, /* SW */
237 {3, NULL, N_("note")}, /* SM */
239 {0, NULL, N_("installation error")}, /* IE */
240 {2, NULL, N_("installation error")}, /* IS */
242 {2, &err_error_count, N_("error")}, /* DE */
243 {2, &err_warning_count, N_("warning")}, /* DW */
245 {0, &err_error_count, N_("error")}, /* ME */
246 {0, &err_warning_count, N_("warning")}, /* MW */
247 {0, NULL, N_("note")}, /* MM */
253 /* Check verbosity level. */
255 if (((class >> ERR_VERBOSITY_SHIFT) & ERR_VERBOSITY_MASK) > err_verbosity)
257 class &= ERR_CLASS_MASK;
259 assert (class >= 0 && class < ERR_CLASS_COUNT);
260 assert (format != NULL);
263 if (e->where.filename && (error_classes[class].flags & ERR_WITH_FILE))
265 ds_printf (&msg, "%s:", e->where.filename);
266 if (e->where.line_number != -1)
267 ds_printf (&msg, "%d:", e->where.line_number);
271 ds_printf (&msg, "%s: ", gettext (error_classes[class].banner));
274 int *count = error_classes[class].count;
279 if (cur_proc && (error_classes[class].flags & ERR_IN_PROCEDURE))
280 ds_printf (&msg, "%s: ", cur_proc);
283 ds_puts (&msg, e->title);
285 ds_vprintf (&msg, format, args);
287 /* FIXME: Check set_messages and set_errors to determine where to
288 send errors and messages.
290 Please note that this is not trivial. We have to avoid an
291 infinite loop in reporting errors that originate in the output
293 dump_message (ds_c_str (&msg), 8, puts_stdout, get_viewwidth());
301 /* Private functions. */
304 /* Write S followed by a newline to stderr. */
306 puts_stderr (const char *s)
309 fputc ('\n', stderr);
313 /* Write S followed by a newline to stdout. */
315 puts_stdout (const char *s)
320 /* Returns 1 if the line must be broken here */
322 compulsory_break(int c)
324 return ( c == '\n' );
327 /* Returns 1 if C is a `break character', that is, if it is a good
328 place to break a message into lines. */
330 char_is_break (int quote, int c)
332 return ((quote && c == DIR_SEPARATOR)
333 || (!quote && (isspace (c) || c == '-' || c == '/')));
336 /* Returns 1 if C is a break character where the break should be made
337 BEFORE the character. */
339 break_before (int quote, int c)
341 return !quote && isspace (c);
344 /* If C is a break character, returns 1 if the break should be made
345 AFTER the character. Does not return a meaningful result if C is
346 not a break character. */
348 break_after (int quote, int c)
350 return !break_before (quote, c);
353 /* If you want very long words that occur at a bad break point to be
354 broken into two lines even if they're shorter than a whole line by
355 themselves, define as 2/3, or 4/5, or whatever fraction of a whole
356 line you think is necessary in order to consider a word long enough
357 to break into pieces. Otherwise, define as 0. See code to grok
358 the details. Do NOT parenthesize the expression! */
359 #define BREAK_LONG_WORD 0
360 /* #define BREAK_LONG_WORD 2/3 */
361 /* #define BREAK_LONG_WORD 4/5 */
363 /* Divides MSG into lines of WIDTH width for the first line and WIDTH
364 - INDENT width for each succeeding line. Each line is dumped
365 through FUNC, which may do with the string what it will. */
367 dump_message (char *msg, unsigned indent, void (*func) (const char *),
372 /* 1 when at a position inside double quotes ("). */
375 /* Buffer for a single line. */
378 /* If the message is short, just print the full thing. */
379 if (strlen (msg) < width)
385 /* Make sure the indent isn't too big relative to the page width. */
386 if (indent > width / 3)
389 buf = local_alloc (width + 2);
391 /* Advance WIDTH characters into MSG.
392 If that's a valid breakpoint, keep it; otherwise, back up.
394 for (cp = msg; (unsigned) (cp - msg) < width - 1 &&
395 ! compulsory_break(*cp); cp++)
399 if (break_after (quote, (unsigned char) *cp))
401 for (cp--; !char_is_break (quote, (unsigned char) *cp) && cp > msg; cp--)
405 if (break_after (quote, (unsigned char) *cp))
409 if (cp <= msg + width * BREAK_LONG_WORD)
410 for (; cp < msg + width - 1; cp++)
422 /* Repeat above procedure for remaining lines. */
425 static int hard_break=0;
430 /* Advance past whitespace. */
432 while ( isspace ((unsigned char) *cp) )
441 /* Advance WIDTH - INDENT characters. */
442 for (cp2 = cp; (unsigned) (cp2 - cp) < width - indent &&
443 *cp2 && !compulsory_break(*cp2); cp2++)
447 if ( compulsory_break(*cp2) )
453 /* Back up if this isn't a breakpoint. */
455 unsigned w = cp2 - cp;
456 if (*cp2 && ! compulsory_break(*cp2) )
457 for (cp2--; !char_is_break (quote, (unsigned char) *cp2) &&
466 if (w == width - indent
467 && (unsigned) (cp2 - cp) <= (width - indent) * BREAK_LONG_WORD)
468 for (; (unsigned) (cp2 - cp) < width - indent && *cp2 ; cp2++)
474 /* Write out the line. */
476 memset (buf, ' ', indent);
477 memcpy (&buf[indent], cp, cp2 - cp);
479 buf[indent + idx + cp2 - cp] = '\0';
489 request_bug_report_and_abort(const char *msg )
492 "******************************************************************\n"
493 "You have discovered a bug in PSPP.\n\n"
494 " Please report this, by sending "
495 "an email to " PACKAGE_BUGREPORT ",\n"
496 "explaining what you were doing when this happened, and including\n"
497 "a sample of your input file which caused it.\n");
500 "Also, please copy the following lines into your bug report:\n\n"
506 "default_config_path: %s\n"
508 "groff_font_path: %s\n"
510 "compiler version: %s\n"
530 fprintf(stderr,"Diagnosis: %s\n",msg);
533 "******************************************************************\n");
539 err_assert_fail(const char *expr, const char *file, int line)
542 snprintf(msg,256,"Assertion failed: %s:%d; (%s)",file,line,expr);
543 request_bug_report_and_abort( msg );