
/********************************************
error.c

libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
based on mawk code coming with the below copyright:

copyright 1991, 1992 Michael D. Brennan

This is a source file for mawk, an implementation of
the AWK programming language.

Mawk is distributed without warranty under the terms of
the GNU General Public License, version 2, 1991.
********************************************/

#include "conf.h"

TODO("this should be gone:")
#include <stdio.h>

#include  "mawk.h"
#include  "scan.h"
#include  "bi_vars.h"
#include  "vargs.h"
#include  "zmalloc.h"
#include  "memory.h"
#include  "cell.h"

#ifndef  EOF
#define  EOF  (-1)
#endif

static void rt_where(mawk_state_t *);
static char *type_to_str(mawk_state_t *, int);


static const char *strerrors[] = {
	"succes",
	"can not open file",
	"internal error: header size mismatch",
	"bad file magic",
	"wrong byte order",
	"version not supported",
	"wrong instruction size",
	"wrong numeric size",
	"can not allocate memory",
	NULL
};

const char *mawk_strerror(mawk_errno_t err)
{
	if (err > 0)
		return "Unknown error (positive)";
	if (err < MAWK_Elast)
		return "Unknown error (negative)";
	return strerrors[-err];
}

#ifdef  NO_VFPRINTF
#define  vfprintf  simple_vfprintf
#endif

/* generic error message with a hook into the system error 
   messages if errnum > 0 */

void mawk_errmsg VA_ALIST2(int, errnum, char *, format)
{
	va_list args;

	fprintf(stderr, "%s: ", MAWK->progname);
	VA_START2(args, int, errnum, char *, format);
	vfprintf(stderr, format, args);
	va_end(args);

	if (errnum > 0)
		fprintf(stderr, " (%s)", strerror(errnum));

	fprintf(stderr, "\n");
}

void mawk_compile_error VA_ALIST(const char *, format)
{
	va_list args;
	const char *s0, *s1;

	/* with multiple program files put program name in
	   error message */
	if (MAWK->ps.pfile_name) {
		s0 = MAWK->ps.pfile_name;
		s1 = ": ";
	}
	else {
		s0 = s1 = "";
	}

	fprintf(stderr, "%s: %s%sline %u: ", MAWK->progname, s0, s1, MAWK->token_lineno);
	VA_START(args, char *, format);
	vfprintf(stderr, format, args);
	va_end(args);
	fprintf(stderr, "\n");
	if (++(MAWK->compile_error_count) == MAX_COMPILE_ERRORS)
		mawk_exit(MAWK, 2);
}

void mawk_rt_error VA_ALIST(const char *, format)
{
	va_list args;

	fprintf(stderr, "%s: run time error: ", MAWK->progname);
	VA_START(args, char *, format);
	vfprintf(stderr, format, args);
	va_end(args);
	putc('\n', stderr);
	rt_where(MAWK);
	MAWK->rt_exit_code = 2;
	mawk_exit(MAWK, 2);
}


void mawk_bozo(MAWK, s)
		 mawk_state_t *MAWK;
		 char *s;
{
	mawk_errmsg(MAWK, 0, "mawk_bozo: %s", s);
#ifdef CELLDEBUG
	abort();
#endif
#ifdef DEBUG
	abort();
#endif
	mawk_exit(MAWK, 3);
}

void mawk_overflow(mawk_state_t *MAWK, char *s, unsigned size)
{
	mawk_errmsg(MAWK, 0, "program limit exceeded: %s size=%u", s, size);
	mawk_exit(MAWK, 2);
}


/* print as much as we know about where a rt error occured */

static void rt_where(mawk_state_t * MAWK)
{
	if (FILENAME->type != C_STRING)
		mawk_cast1_to_str(MAWK, FILENAME);

	fprintf(stderr, "\tFILENAME=\"%s\" FNR=%u NR=%u\n", string(FILENAME)->str, MAWK->rt_fnr, MAWK->rt_nr);
}

/* run time */
void mawk_rt_overflow(mawk_state_t *MAWK, char *s, unsigned size)
{
	mawk_errmsg(MAWK, 0, "program limit exceeded: %s size=%u", s, size);
	rt_where(MAWK);
	mawk_exit(MAWK, 2);
}

static char *type_to_str(mawk_state_t *MAWK, int type)
{
	char *retval;

	switch (type) {
	case ST_VAR:
		retval = "variable";
		break;
	case ST_ARRAY:
		retval = "array";
		break;
	case ST_FUNCT:
		retval = "function";
		break;
	case ST_LOCAL_VAR:
		retval = "local variable";
		break;
	case ST_LOCAL_ARRAY:
		retval = "local array";
		break;
	default:
		mawk_bozo(MAWK, "type_to_str");
	}
	return retval;
}

/* emit an error message about a type clash */
void mawk_type_error(mawk_state_t *MAWK, SYMTAB *p)
{
	mawk_compile_error(MAWK, "illegal reference to %s %s", type_to_str(MAWK, p->type), p->name);
}



#ifdef  NO_VFPRINTF

/* a minimal vfprintf  */
int simple_vfprintf(FILE *fp, char *format, va_list argp)
{
	char *q, *p, *t;
	int l_flag;
	char xbuff[64];

	q = format;
	xbuff[0] = '%';

	while (*q != 0) {
		if (*q != '%') {
			putc(*q, fp);
			q++;
			continue;
		}

		/* mark the start with p */
		p = ++q;
		t = xbuff + 1;

		if (*q == '-')
			*t++ = *q++;
		while (scan_code[*(unsigned char *) q] == SC_DIGIT)
			*t++ = *q++;
		if (*q == '.') {
			*t++ = *q++;
			while (scan_code[*(unsigned char *) q] == SC_DIGIT)
				*t++ = *q++;
		}

		if (*q == 'l') {
			l_flag = 1;
			*t++ = *q++;
		}
		else
			l_flag = 0;


		*t = *q++;
		t[1] = 0;

		switch (*t) {
		case 'c':
		case 'd':
		case 'o':
		case 'x':
		case 'u':
			if (l_flag)
				fprintf(fp, xbuff, va_arg(argp, long));
			else
				fprintf(fp, xbuff, va_arg(argp, int));
			break;

		case 's':
			fprintf(fp, xbuff, va_arg(argp, char *));
			break;

#ifndef MAWK_NO_FLOAT
		case 'g':
		case 'f':
			fprintf(fp, xbuff, va_arg(argp, double));
			break;
#endif

		default:
			putc('%', fp);
			q = p;
			break;
		}
	}
	return 0;											/* shut up */
}

#endif /* USE_SIMPLE_VFPRINTF */


void mawk_set_errno(mawk_state_t * MAWK, const char *error)
{
	mawk_cell_destroy(MAWK, ERRNO);
	ERRNO->type = C_STRING;
	ERRNO->ptr = (PTR) mawk_new_STRING(MAWK, error);
}
