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.