// Written in the D programming language

module std.asserterror;

import std.c.stdio;
import std.c.stdlib;
import std.contracts;

class AssertError : Error
{
    uint linnum;
    char[] filename;

    this(char[] filename, uint linnum)
    {
	this(filename, linnum, null);
    }

    this(char[] filename, uint linnum, char[] msg)
    {
	this.linnum = linnum;
	this.filename = filename;

	char* buffer;
	size_t len;
	int count;

	/* This code is careful to not use gc allocated memory,
	 * as that may be the source of the problem.
	 * Instead, stick with C functions.
	 */

	len = 23 + filename.length + uint.sizeof * 3 + msg.length + 1;
	buffer = cast(char*)std.c.stdlib.malloc(len);
	if (buffer is null)
	    super("AssertError no memory");
	else
	{
	    version (Win32) alias _snprintf snprintf;
	    count = snprintf(buffer, len, "AssertError Failure %.*s(%u) %.*s",
		filename, linnum, msg);
	    if (count >= len || count == -1)
	    {	super("AssertError internal failure");
		std.c.stdlib.free(buffer);
	    }
	    else
            {
                // casting is fine because buffer is unaliased
                auto s = buffer[0 .. count];
		super(assumeUnique(s));
            }
	}
    }

    ~this()
    {
	if (msg.ptr && msg[12] == 'F')	// if it was allocated with malloc()
	{   std.c.stdlib.free(cast(char*)msg.ptr);
	    msg = null;
	}
    }
}


/********************************************
 * Called by the compiler generated module assert function.
 * Builds an AssertError exception and throws it.
 */

extern (C) static void _d_assert(char[] filename, uint line)
{
    //printf("_d_assert(%s, %d)\n", cast(char *)filename, line);
    AssertError a = new AssertError(filename, line);
    //printf("assertion %p created\n", a);
    throw a;
}

extern (C) static void _d_assert_msg(char[] msg, char[] filename, uint line)
{
    //printf("_d_assert_msg(%s, %d)\n", cast(char *)filename, line);
    AssertError a = new AssertError(filename, line, msg);
    //printf("assertion %p created\n", a);
    throw a;
}

