2 /* Copyright (c) 1995, 1997, 1999, 2000, 2001, 2006 by Arkkra Enterprises */
3 /* All rights reserved */
5 /* various functions for printing error messages and exiting when
18 #include <BBEdit_Streams.h>
21 extern void exit P((int status));
23 int debug_on P((int level));
26 extern void abort P((void));
31 static void error_header P((char *filename, int lineno, char * errtype));
33 /* Print a message for a user error, and exit with the value of Errorcount,
34 * or of MAX_ERRORS if > MAX_ERRORS */
40 ufatal(char *format, ...)
45 ufatal(format, va_alist)
47 char *format; /* printf style format */
55 /* we now have one more error */
58 /* print the specified message with a newline */
60 va_start(args, format);
65 #ifndef UNIX_LIKE_FILES
69 (void) fprintf(stderr, "\nfatal user error: ");
70 (void) vfprintf(stderr, format, args);
72 (void) fprintf(stderr, "\n");
77 /* Print a message with filename and linenumber for a user error,
78 * and exit with the value of Errorcount, or of MAX_ERRORS if > MAX_ERRORS */
84 l_ufatal(char *filename, int lineno, char *format, ...)
89 l_ufatal(filename, lineno, format, va_alist)
93 char *format; /* printf style format */
101 /* we now have one more error */
104 /* print the specified message with a newline */
106 va_start(args, format);
111 #ifndef UNIX_LIKE_FILES
115 error_header(filename, lineno, "fatal user error");
117 (void) vfprintf(stderr, format, args);
119 (void) fprintf(stderr, "\n");
122 AppendError(filename, lineno);
129 /* Print a message for a program internal error and exit with MAX_ERRORS */
137 pfatal(char *format, ...)
142 pfatal(format, va_alist)
153 va_start(args, format);
158 #ifndef UNIX_LIKE_FILES
162 /* print specified message with newline */
163 (void) fprintf(stderr, "\nfatal internal error: ");
164 (void) vfprintf(stderr, format, args);
166 (void) fprintf(stderr, "\n");
169 (void) fprintf(stderr, "creating a core dump\n");
173 Errorcount = MAX_ERRORS;
178 /* fatal error with line number and file name. Note that this should be the
179 * line number and file in the program, not the input file, ie, __LINE__
187 l_pfatal(char *filename, int lineno, char *format, ...)
192 l_pfatal(filename, lineno, format, va_alist)
194 char *filename; /* name of program file */
195 int lineno; /* pgm line where error was discovered */
196 char *format; /* printf format */
205 va_start(args, format);
210 error_header(filename, lineno, "fatal internal error");
211 pfatal(format, args);
216 /* error exit for the common problem of malloc failures */
219 l_no_mem(filename, lineno)
225 l_pfatal(filename, lineno, "memory allocation failed");
229 /* error exit for common error of not being able to open a specified file */
237 ufatal("can't open '%s'", filename);
241 /* Exit with exit code being the number of errors, unless there were
242 * too many of them to fit in an exit code, in which case MAX_ERRORS
243 * is used. MAX_ERRORS is used for internal errors. */
249 exit(Errorcount > MAX_ERRORS ? MAX_ERRORS : Errorcount);
253 /* print a warning message */
260 warning(char *format, ...)
265 warning(format, va_alist)
275 if (Score.warn == NO) {
279 va_start(args, format);
284 (void) fprintf(stderr, "warning: ");
285 (void) vfprintf(stderr, format, args);
286 (void) fprintf(stderr, "\n");
290 AppendWarning((char *) 0, -1);
295 /* warning message with file name and line number */
302 l_warning(char * filename, int lineno, char *format, ...)
307 l_warning(filename, lineno, format, va_alist)
309 char *filename; /* name of program file */
310 int lineno; /* pgm line where error was discovered */
311 char *format; /* printf format */
319 if (Score.warn == NO) {
323 va_start(args, format);
328 error_header(filename, lineno, "warning");
329 (void) vfprintf(stderr, format, args);
330 (void) fprintf(stderr, "\n");
334 AppendWarning(filename, lineno);
339 /* varargs version of yyerror, passing a file and linenumber (or -1 for the
340 * lineno if you don't want a filename and linenumber printed) */
347 l_yyerror(char *fname, int lineno, char *format, ...)
352 l_yyerror(fname, lineno, format, va_alist)
365 /* if linenumber is zero or negative, assume this is special case of
366 * not being associated with a specific line, so don't print
369 /* There are cases where the parser has already looked ahead
370 * to find the newline in order to fully match a grammar
371 * rule. When that happens, the line number will already have
372 * been incremented and our message would be off by one.
373 * So catch that case and compensate. */
374 if ( (lineno == yylineno) && (fname == Curr_filename) &&
375 Last_was_newline == YES) {
378 error_header(fname, lineno, "error");
382 va_start(args, format);
387 (void) vfprintf(stderr, format, args);
389 (void) fprintf(stderr, "\n");
391 /* if doing macro expansion, also tell where macro was defined */
395 AppendError(fname, lineno);
404 /* print a debugging message if corresponding debugging bit is on */
411 debug(int level, char *format, ...)
416 debug(level, format, va_alist)
418 int level; /* debugging flag bitmap */
419 char *format; /* printf style format */
427 if (debug_on(level)) {
429 va_start(args, format);
433 (void) vfprintf(stderr, format, args);
435 (void) fprintf(stderr, "\n");
440 /* return AND of Debuglevel and argument. Useful for other debug functions
441 * that want to see if a given debug level is currently turned on */
449 return(Debuglevel & level);
452 /* if we get an error while doing rational arithmetic, we are in deep
453 * trouble, so print message and get out. */
464 pfatal("rational overflow");
469 pfatal("rational division by zero");
474 pfatal("invalid rational number parameter");
479 pfatal("error in rational arithmetic routines");
486 /* Print header for an error report. If the error is associated with a
487 * particular line, the file name and line number and the text of the line
488 * is printed, but only on the first of multiple errors for the same line.
489 * If not associated with any line, a blank line is produced.
493 error_header(filename, lineno, errtype)
497 char * errtype; /* "warning" or "error" etc */
500 static char *cached_filename = 0;
501 static int cached_lineno = -1;
503 if (filename == 0 || lineno <= 0) {
504 (void) fprintf(stderr, "\n");
508 /* We print the text of the offending line, unless it is the
509 * same as the last error, in which case we could have already
510 * printed it, so no need to print again. */
511 if (cached_filename != filename || cached_lineno != lineno) {
512 (void) fprintf(stderr,"\n%s: line %d:\n", filename, lineno);
513 print_offending_line(filename, lineno);
515 (void) fprintf(stderr,"%s: ", errtype);
516 cached_filename = filename;
517 cached_lineno = lineno;
521 /* Print the text of input line where error was found. */
524 print_offending_line(filename, lineno)
530 /* We cache file info to save time when multiple errors */
532 static char *prev_filename = 0;
533 static int prev_lineno = 0;
534 int inp; /* a byte read from file */
535 int skipcount; /* how many lines to skip past */
537 /* We try to reuse already opened file to save time,
538 * but need to open new file when necessary. */
539 if (f == 0 || prev_filename != filename) {
540 /* close any previously open file */
544 /* Note that if Mup is reading from stdin, we will try to
545 * open a file entitled "stdin" here. That will almost
546 * certainly fail, but we can't easily get the line from
547 * stdin anyway, so user just won't get the context in that
548 * case. People who are having Mup read from stdin are probably
549 * savvy enough that this isn't a big problem. (We never used
550 * to print this context ever, and no one complained.)
551 * So the only weird case is if the user happens to have a
552 * file whose name is literally "stdin" but the actual stdin
553 * being read is some other file, in which case they'll get
554 * garbage. But anyone using stdin for a file name is probably
555 * smart enough to figure out the strange results in that case.
556 * In the case of include files found via $MUPPATH,
557 * filename will have already been expanded to a full path,
558 * so we don't have to do anything special here for them.
560 if ((f = fopen(filename, "r")) == 0) {
563 skipcount = lineno - 1;
564 prev_filename = filename;
566 else if (lineno > prev_lineno) {
567 /* We can continue where we left off in the file */
568 skipcount = lineno - prev_lineno - 1;
571 /* Earlier line in same file; easiest to just start over.
572 * This could happen, because sometimes we don't realize
573 * there is an error until a later line (E.g., only when
574 * getting to bar line we find inconsistency in the
575 * contents of the bar.) */
577 skipcount = lineno - 1;
580 /* Skip to the line of interest and print it. */
581 for (inp = 0; skipcount > 0; skipcount--) {
582 /* We read byte-by-byte so we don't need to guess
583 * how big a buffer to use to hold a line.
585 while ((inp = getc(f)) != '\n' && inp != EOF) {
593 (void) fprintf(stderr, " ");
594 while ((inp = getc(f)) != '\n' && inp != EOF) {
599 prev_lineno = lineno;
600 /* Note that we leave the file open, to save time
601 * in case we need to read more from it
602 * due to additional errors from the same file.