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, ...)
84 ds_init (NULL, &buf, 1024);
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);
107 /* Terminate due to fatal error in input. */
114 fprintf (stderr, "%s: %s\n", pgmname,
115 _("Terminating NOW due to a fatal error!"));
120 /* Terminate unless we're interactive or will go interactive when the
121 file is over with. */
125 if (getl_reading_script)
127 if (getl_interactive)
134 /* File locator stack functions. */
136 /* Pushes F onto the stack of file locations. */
138 err_push_file_locator (const struct file_locator *f)
140 if (nfile_loc >= mfile_loc)
147 file_loc = xrealloc (file_loc, mfile_loc * sizeof *file_loc);
150 file_loc[nfile_loc++] = f;
153 /* Pops F off the stack of file locations.
154 Argument F is only used for verification that that is actually the
155 item on top of the stack. */
157 err_pop_file_locator (const struct file_locator *f)
159 assert (nfile_loc >= 0 && file_loc[nfile_loc - 1] == f);
163 /* Puts the current file and line number in F, or NULL and -1 if
166 err_location (struct file_locator *f)
169 *f = *file_loc[nfile_loc - 1];
171 getl_location (&f->filename, &f->line_number);
174 /* Obscure public functions. */
176 /* Writes a blank line to the error device(s).
177 FIXME: currently a no-op. */
183 /* Checks whether we've had so many errors that it's time to quit
184 processing this syntax file. If so, then take appropriate
187 err_check_count (void)
189 int error_class = getl_interactive ? MM : FE;
191 if (get_errorbreak() && err_error_count)
192 msg (error_class, _("Terminating execution of syntax file due to error."));
193 else if (err_error_count > get_mxerrs() )
194 msg (error_class, _("Errors (%d) exceeds limit (%d)."),
195 err_error_count, get_mxerrs());
196 else if (err_error_count + err_warning_count > get_mxwarns() )
197 msg (error_class, _("Warnings (%d) exceed limit (%d)."),
198 err_error_count + err_warning_count, get_mxwarns() );
205 /* Some machines are broken. Compensate. */
207 #define EXIT_SUCCESS 0
211 #define EXIT_FAILURE 1
214 static int terminating;
216 /* Halt-catch-fire. SUCCESS should be nonzero if exiting successfully
217 or zero if not. Despite the name, this is the usual way to finish,
218 successfully or not. */
220 err_hcf (int success)
224 getl_uninitialize ();
228 exit (success ? EXIT_SUCCESS : EXIT_FAILURE);
231 static void puts_stdout (const char *s);
232 static void dump_message (char *errbuf, unsigned indent,
233 void (*func) (const char *), unsigned width);
236 err_vmsg (const struct error *e)
241 ERR_IN_PROCEDURE = 01, /* 1=Display name of current procedure. */
242 ERR_WITH_FILE = 02, /* 1=Display filename and line number. */
245 /* Describes one class of error. */
248 int flags; /* Zero or more of ERR_*. */
249 int *count; /* Counting category. */
250 const char *banner; /* Banner. */
253 static const struct error_class error_classes[ERR_CLASS_COUNT] =
255 {0, NULL, N_("fatal")}, /* FE */
257 {3, &err_error_count, N_("error")}, /* SE */
258 {3, &err_warning_count, N_("warning")}, /* SW */
259 {3, NULL, N_("note")}, /* SM */
261 {0, NULL, N_("installation error")}, /* IE */
262 {2, NULL, N_("installation error")}, /* IS */
264 {2, &err_error_count, N_("error")}, /* DE */
265 {2, &err_warning_count, N_("warning")}, /* DW */
267 {0, &err_error_count, N_("error")}, /* ME */
268 {0, &err_warning_count, N_("warning")}, /* MW */
269 {0, NULL, N_("note")}, /* MM */
275 /* Check verbosity level. */
277 if (((class >> ERR_VERBOSITY_SHIFT) & ERR_VERBOSITY_MASK) > err_verbosity)
279 class &= ERR_CLASS_MASK;
281 assert (class >= 0 && class < ERR_CLASS_COUNT);
282 assert (e->text != NULL);
284 ds_init (NULL, &msg, 64);
285 if (e->where.filename && (error_classes[class].flags & ERR_WITH_FILE))
287 ds_printf (&msg, "%s:", e->where.filename);
288 if (e->where.line_number != -1)
289 ds_printf (&msg, "%d:", e->where.line_number);
290 ds_putchar (&msg, ' ');
293 ds_printf (&msg, "%s: ", gettext (error_classes[class].banner));
296 int *count = error_classes[class].count;
301 if (cur_proc && (error_classes[class].flags & ERR_IN_PROCEDURE))
302 ds_printf (&msg, "%s: ", cur_proc);
305 ds_concat (&msg, e->title);
307 ds_concat (&msg, e->text);
309 /* FIXME: Check set_messages and set_errors to determine where to
310 send errors and messages.
312 Please note that this is not trivial. We have to avoid an
313 infinite loop in reporting errors that originate in the output
315 dump_message (ds_value (&msg), 8, puts_stdout, get_viewwidth());
319 if (e->class == FE && !terminating)
323 /* Private functions. */
326 /* Write S followed by a newline to stderr. */
328 puts_stderr (const char *s)
331 fputc ('\n', stderr);
335 /* Write S followed by a newline to stdout. */
337 puts_stdout (const char *s)
342 /* Returns 1 if the line must be broken here */
344 compulsory_break(int c)
346 return ( c == '\n' );
349 /* Returns 1 if C is a `break character', that is, if it is a good
350 place to break a message into lines. */
352 char_is_break (int quote, int c)
354 return ((quote && c == DIR_SEPARATOR)
355 || (!quote && (isspace (c) || c == '-' || c == '/')));
358 /* Returns 1 if C is a break character where the break should be made
359 BEFORE the character. */
361 break_before (int quote, int c)
363 return !quote && isspace (c);
366 /* If C is a break character, returns 1 if the break should be made
367 AFTER the character. Does not return a meaningful result if C is
368 not a break character. */
370 break_after (int quote, int c)
372 return !break_before (quote, c);
375 /* If you want very long words that occur at a bad break point to be
376 broken into two lines even if they're shorter than a whole line by
377 themselves, define as 2/3, or 4/5, or whatever fraction of a whole
378 line you think is necessary in order to consider a word long enough
379 to break into pieces. Otherwise, define as 0. See code to grok
380 the details. Do NOT parenthesize the expression! */
381 #define BREAK_LONG_WORD 0
382 /* #define BREAK_LONG_WORD 2/3 */
383 /* #define BREAK_LONG_WORD 4/5 */
385 /* Divides MSG into lines of WIDTH width for the first line and WIDTH
386 - INDENT width for each succeeding line. Each line is dumped
387 through FUNC, which may do with the string what it will. */
389 dump_message (char *msg, unsigned indent, void (*func) (const char *),
394 /* 1 when at a position inside double quotes ("). */
397 /* Buffer for a single line. */
400 /* If the message is short, just print the full thing. */
401 if (strlen (msg) < width)
407 /* Make sure the indent isn't too big relative to the page width. */
408 if (indent > width / 3)
411 buf = local_alloc (width + 2);
413 /* Advance WIDTH characters into MSG.
414 If that's a valid breakpoint, keep it; otherwise, back up.
416 for (cp = msg; (unsigned) (cp - msg) < width - 1 &&
417 ! compulsory_break(*cp); cp++)
421 if (break_after (quote, (unsigned char) *cp))
423 for (cp--; !char_is_break (quote, (unsigned char) *cp) && cp > msg; cp--)
427 if (break_after (quote, (unsigned char) *cp))
431 if (cp <= msg + width * BREAK_LONG_WORD)
432 for (; cp < msg + width - 1; cp++)
444 /* Repeat above procedure for remaining lines. */
447 static int hard_break=0;
452 /* Advance past whitespace. */
454 while ( isspace ((unsigned char) *cp) )
463 /* Advance WIDTH - INDENT characters. */
464 for (cp2 = cp; (unsigned) (cp2 - cp) < width - indent &&
465 *cp2 && !compulsory_break(*cp2); cp2++)
469 if ( compulsory_break(*cp2) )
475 /* Back up if this isn't a breakpoint. */
477 unsigned w = cp2 - cp;
478 if (*cp2 && ! compulsory_break(*cp2) )
479 for (cp2--; !char_is_break (quote, (unsigned char) *cp2) &&
488 if (w == width - indent
489 && (unsigned) (cp2 - cp) <= (width - indent) * BREAK_LONG_WORD)
490 for (; (unsigned) (cp2 - cp) < width - indent && *cp2 ; cp2++)
496 /* Write out the line. */
498 memset (buf, ' ', indent);
499 memcpy (&buf[indent], cp, cp2 - cp);
503 buf[indent + idx + cp2 - cp] = '\n';
506 buf[indent + idx + cp2 - cp] = '\0';