/* Written by David MacKenzie <djm@gnu.ai.mit.edu>.  */

#include "system.h"
#include "error.h"
#include "progname.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

/* If |NULL|, error will flush |stdout|, then print on |stderr| the
   program name, a colon and a space.  Otherwise, error will call this
   function without parameters instead.  */
void (*error_print_progname)(void);

/* This variable is incremented each time |error| is called.  */
unsigned int error_message_count;


/* Return non-zero if |fd| is open.  */
static int
is_open(int fd) {
    return 0 <= fcntl(fd, F_GETFL);
}

static void
flush_stdout(void) {
    if (is_open(1))
        fflush(stdout);
}

static void
print_errno_message(int errnum) {
    char const *s;
    char errbuf[1024];
    if (strerror_r(errnum, errbuf, sizeof errbuf) == 0)
        s = errbuf;
    else
        s = 0;
    if (!s)
        s = "Unknown system error";
    fprintf(stderr, ": %s", s);
}

static void
error_tail(int status, int errnum, const char *message, va_list args) {
    vfprintf(stderr, message, args);
    va_end (args);

    ++error_message_count;
    if (errnum)
        print_errno_message(errnum);
    putc ('\n', stderr);
    fflush(stderr);
    if (status)
        exit(status);
}


/* Print the program name and error message |message|, which is a
   printf-style format string with optional args.  If |errnum| is
   nonzero, print its corresponding system error message.  Exit with
   status |status| if it is nonzero.  */
void
error(int status, int errnum, const char *message, ...) {
    va_list args;
    flush_stdout();
    if (error_print_progname)
        (*error_print_progname)();
    else {
        fprintf(stderr, "%s: ", get_program_name());
    }

    va_start (args, message);
    error_tail(status, errnum, message, args);
}