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
20 /* AIX requires this to be the first thing in the file. */
23 #define alloca __builtin_alloca
31 #ifndef alloca /* predefined by HP cc +Olibcalls */
54 int err_warning_count;
56 int err_already_flagged;
60 /* File locator stack. */
61 static const struct file_locator **file_loc;
62 static int nfile_loc, mfile_loc;
64 /* Fairly common public functions. */
66 /* Writes error message in CLASS, with title TITLE and text FORMAT,
67 formatted with printf, to the standard places. */
69 tmsg (int class, const char *title, const char *format, ...)
73 /* Format the message into BUF. */
77 va_start (args, format);
78 vsnprintf (buf, 1024, format, args);
82 /* Output the message. */
87 err_location (&e.where);
94 /* Writes error message in CLASS, with text FORMAT, formatted with
95 printf, to the standard places. */
97 msg (int class, const char *format, ...)
101 /* Format the message into BUF. */
105 va_start (args, format);
106 vsnprintf (buf, 1024, format, args);
110 /* Output the message. */
115 err_location (&e.where);
122 /* Terminate due to fatal error in input. */
129 fprintf (stderr, "%s: %s\n", pgmname,
130 _("Terminating NOW due to a fatal error!"));
135 /* Terminate unless we're interactive or will go interactive when the
136 file is over with. */
140 if (getl_reading_script)
142 if (getl_interactive)
149 /* File locator stack functions. */
151 /* Pushes F onto the stack of file locations. */
153 err_push_file_locator (const struct file_locator *f)
155 if (nfile_loc >= mfile_loc)
162 file_loc = xrealloc (file_loc, mfile_loc * sizeof *file_loc);
165 file_loc[nfile_loc++] = f;
168 /* Pops F off the stack of file locations.
169 Argument F is only used for verification that that is actually the
170 item on top of the stack. */
172 err_pop_file_locator (const struct file_locator *f)
174 assert (nfile_loc >= 0 && file_loc[nfile_loc - 1] == f);
178 /* Puts the current file and line number in F, or NULL and -1 if
181 err_location (struct file_locator *f)
184 *f = *file_loc[nfile_loc - 1];
186 getl_location (&f->filename, &f->line_number);
189 /* Obscure public functions. */
191 /* Writes a blank line to the error device(s).
192 FIXME: currently a no-op. */
198 /* Checks whether we've had so many errors that it's time to quit
199 processing this syntax file. If so, then take appropriate
202 err_check_count (void)
204 int error_class = getl_interactive ? MM : FE;
206 if (set_errorbreak && err_error_count)
207 msg (error_class, _("Terminating execution of syntax file due to error."));
208 else if (err_error_count > set_mxerrs)
209 msg (error_class, _("Errors (%d) exceeds limit (%d)."),
210 err_error_count, set_mxerrs);
211 else if (err_error_count + err_warning_count > set_mxwarns)
212 msg (error_class, _("Warnings (%d) exceed limit (%d)."),
213 err_error_count + err_warning_count, set_mxwarns);
221 static void induce_segfault (void);
224 /* Some machines are broken. Compensate. */
226 #define EXIT_SUCCESS 0
230 #define EXIT_FAILURE 1
233 static int terminating;
235 /* Halt-catch-fire. SUCCESS should be nonzero if exiting successfully
236 or zero if not. Despite the name, this is the usual way to finish,
237 successfully or not. */
239 err_hcf (int success)
243 getl_uninitialize ();
252 exit (success ? EXIT_SUCCESS : EXIT_FAILURE);
255 static void puts_stdout (const char *s);
256 static void dump_message (char *errbuf, unsigned indent,
257 void (*func) (const char *), unsigned width);
260 err_vmsg (const struct error *e)
265 ERR_IN_PROCEDURE = 01, /* 1=Display name of current procedure. */
266 ERR_WITH_FILE = 02, /* 1=Display filename and line number. */
269 /* Describes one class of error. */
272 int flags; /* Zero or more of MSG_*. */
273 int *count; /* Counting category. */
274 const char *banner; /* Banner. */
277 static const struct error_class error_classes[ERR_CLASS_COUNT] =
279 {0, NULL, N_("fatal")}, /* FE */
281 {3, &err_error_count, N_("error")}, /* SE */
282 {3, &err_warning_count, N_("warning")}, /* SW */
283 {3, NULL, N_("note")}, /* SM */
285 {0, NULL, N_("installation error")}, /* IE */
286 {2, NULL, N_("installation error")}, /* IS */
288 {2, NULL, N_("error")}, /* DE */
289 {2, NULL, N_("warning")}, /* DW */
291 {0, NULL, N_("error")}, /* ME */
292 {0, NULL, N_("warning")}, /* MW */
293 {0, NULL, N_("note")}, /* MM */
299 /* Check verbosity level. */
301 if (((class >> ERR_VERBOSITY_SHIFT) & ERR_VERBOSITY_MASK) > err_verbosity)
303 class &= ERR_CLASS_MASK;
305 assert (class >= 0 && class < ERR_CLASS_COUNT);
306 assert (e->text != NULL);
308 ds_init (NULL, &msg, 64);
309 if (e->where.filename && (error_classes[class].flags & ERR_WITH_FILE))
311 ds_printf (&msg, "%s:", e->where.filename);
312 if (e->where.line_number != -1)
313 ds_printf (&msg, "%d:", e->where.line_number);
314 ds_putchar (&msg, ' ');
317 ds_printf (&msg, "%s: ", gettext (error_classes[class].banner));
320 int *count = error_classes[class].count;
325 if (cur_proc && (error_classes[class].flags & ERR_IN_PROCEDURE))
326 ds_printf (&msg, "%s: ", cur_proc);
329 ds_concat (&msg, e->title);
331 ds_concat (&msg, e->text);
333 /* FIXME: Check set_messages and set_errors to determine where to
334 send errors and messages.
336 Please note that this is not trivial. We have to avoid an
337 infinite loop in reporting errors that originate in the output
339 dump_message (ds_value (&msg), 8, puts_stdout, set_viewwidth);
343 if (e->class == FE && !terminating)
347 /* Private functions. */
350 /* Write S followed by a newline to stderr. */
352 puts_stderr (const char *s)
355 fputc ('\n', stderr);
359 /* Write S followed by a newline to stdout. */
361 puts_stdout (const char *s)
366 /* Returns 1 if C is a `break character', that is, if it is a good
367 place to break a message into lines. */
369 char_is_break (int quote, int c)
371 return ((quote && c == DIR_SEPARATOR)
372 || (!quote && (isspace (c) || c == '-' || c == '/')));
375 /* Returns 1 if C is a break character where the break should be made
376 BEFORE the character. */
378 break_before (int quote, int c)
380 return !quote && isspace (c);
383 /* If C is a break character, returns 1 if the break should be made
384 AFTER the character. Does not return a meaningful result if C is
385 not a break character. */
387 break_after (int quote, int c)
389 return !break_before (quote, c);
392 /* If you want very long words that occur at a bad break point to be
393 broken into two lines even if they're shorter than a whole line by
394 themselves, define as 2/3, or 4/5, or whatever fraction of a whole
395 line you think is necessary in order to consider a word long enough
396 to break into pieces. Otherwise, define as 0. See code to grok
397 the details. Do NOT parenthesize the expression! */
398 #define BREAK_LONG_WORD 0
399 /* #define BREAK_LONG_WORD 2/3 */
400 /* #define BREAK_LONG_WORD 4/5 */
402 /* Divides MSG into lines of WIDTH width for the first line and WIDTH
403 - INDENT width for each succeeding line. Each line is dumped
404 through FUNC, which may do with the string what it will. */
406 dump_message (char *msg, unsigned indent, void (*func) (const char *),
411 /* 1 when at a position inside double quotes ("). */
414 /* Buffer for a single line. */
417 /* If the message is short, just print the full thing. */
418 if (strlen (msg) < width)
424 /* Make sure the indent isn't too big relative to the page width. */
425 if (indent > width / 3)
428 buf = local_alloc (width + 1);
430 /* Advance WIDTH characters into MSG.
431 If that's a valid breakpoint, keep it; otherwise, back up.
433 for (cp = msg; (unsigned) (cp - msg) < width - 1; cp++)
437 if (break_after (quote, (unsigned char) *cp))
439 for (cp--; !char_is_break (quote, (unsigned char) *cp) && cp > msg; cp--)
443 if (break_after (quote, (unsigned char) *cp))
447 if (cp <= msg + width * BREAK_LONG_WORD)
448 for (; cp < msg + width - 1; cp++)
459 /* Repeat above procedure for remaining lines. */
464 /* Advance past whitespace. */
465 while (isspace ((unsigned char) *cp))
470 /* Advance WIDTH - INDENT characters. */
471 for (cp2 = cp; (unsigned) (cp2 - cp) < width - indent && *cp2; cp2++)
475 /* Back up if this isn't a breakpoint. */
477 unsigned w = cp2 - cp;
479 for (cp2--; !char_is_break (quote, (unsigned char) *cp2) && cp2 > cp;
484 if (w == width - indent
485 && (unsigned) (cp2 - cp) <= (width - indent) * BREAK_LONG_WORD)
486 for (; (unsigned) (cp2 - cp) < width - indent && *cp2; cp2++)
491 /* Write out the line. */
492 memset (buf, ' ', indent);
493 memcpy (&buf[indent], cp, cp2 - cp);
494 buf[indent + cp2 - cp] = '\0';
504 /* Causes a segfault in order to force Checker to print a stack
507 induce_segfault (void)
510 "\t*********************\n"
511 "\t* INDUCING SEGFAULT *\n"
512 "\t*********************\n"), stdout);