% Copyright 1991 by Norman Ramsey.  All rights reserved.
% See file COPYRIGHT for more information.
\subsection{Error messages}
Here is a big set of functions that other places can call to issue
error messages.

It might be worth implementing these as macros so they could indicate
the file name and line number in the source of where they were called.

[[errorlevel]] is an integer that says how bad the worst error so far
has been.
[[newerrorlevel]] will update it conditionally.
Some day we should hide it and give the world a function call that
queries it.
<<*>>=
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "errors.h"

<<C functions>>
@
I track degrees of error as they occur.
<<header>>=
enum errorlevel { Normal=0, Warning, Error, Fatal, Impossible };
extern enum errorlevel errorlevel;
@ %def errorlevel
<<C functions>>=
enum errorlevel errorlevel = Normal;
@
The rest is just varying flavors of error messages.
<<header>>=
void errormsg(enum errorlevel level, char *s, ...);
#define overflow(S) errormsg(Fatal,"Capacity exceeded: %s", S)
#define impossible(S) errormsg(Impossible, "This can't happen: %s", S)
#define checkptr(P) do { if (!(P)) overflow("memory"); } while (0)
@ %def errormsg overflow impossible checkptr
<<C functions>>=
void errormsg(enum errorlevel level, char *s,...) {
    va_list args;                       /* see K&R, page 174 */
    va_start(args,s);
    <<set [[errorlevel]] and print [[s]] with [[args]]>>
    va_end(args);
    if (level >= Fatal)
        exit(level);
}
@ %def errormsg
<<header>>=
void errorat(char *filename, int lineno, enum errorlevel level, char *s, ...);
<<C functions>>=
void errorat(char *filename, int lineno, enum errorlevel level, char *s, ...) {
    va_list args;                       /* see K&R, page 174 */
    va_start(args,s);
    fprintf(stderr, "\"%s\", line %d: ", filename, lineno);
    <<set [[errorlevel]] and print [[s]] with [[args]]>>
    va_end(args);
    if (level >= Fatal)
        exit(level);
}
@ %def errorat
<<set [[errorlevel]] and print [[s]] with [[args]]>>=
if (level > errorlevel)
    errorlevel = level;
vfprintf(stderr, s, args);
fprintf(stderr,"\n");
@
Some older machines don't do [[vfprintf]]; here's an implementation:
<<crock for non-ANSI machines>>=
extern int _doprnt(const char *format, va_list args, FILE *stream);

int vfprintf(FILE *stream, const char *format, va_list arg) {
    return _doprnt(format,arg,stream);
}


