import std.string;

extern (C) putchar (const c : char);
extern (C) printf (const c : p!char, ...);

def print (c : char) : void
    putchar (c);

def print (const s : string) : void {
    if (s is null) {        
        putchar ('n');
        putchar ('u');
        putchar ('l');
        putchar ('l');
    } else for (it in s) putchar (it);
}


def print (i : long) : void {
    printf (("%ld".toStringz).ptr, i);
}

def print (i : int) : void {
    printf (("%d".toStringz).ptr, i);
}

def print (i : short) : void {
    printf (("%hd".toStringz).ptr, i);
}

def print (i : byte) : void {
    printf (("%hhx".toStringz).ptr, i);
}

def print (i : ulong) : void {
    printf (("%lu".toStringz).ptr, i);
}

def print (i : p!void) : void {
    printf (("%lu".toStringz).ptr, i);
}

def print (T) (i : p!T) : void {
    printf (("%lu".toStringz).ptr, i);
}

def print (i : uint) : void {
    printf (("%u".toStringz).ptr, i);
}

def print (i : ushort) : void {
    printf (("%hu".toStringz).ptr, i);
}

def print (i : ubyte) : void {
    printf (("%hhx".toStringz).ptr, i);
}

def print (a : float, prec : long) {
    printf (("%.*lf".toStringz).ptr, prec, a);
}

def print (f : float) {
    printf (("%lf".toStringz).ptr, f);
}

def print (b : bool) {
    if (b) print ("true");
    else print ("false");
}

def print (T of [U], U) (a : T) {
    import std.conv;
    print (a.to!string);
}

def print if (is (T : struct)) (T) (a : T) {
    import std.conv;
    print (a.to!string);
}

def println (T) (i : T) {
    print (i);
    print ('\n');
}

def println (T) (const i : T) {
    print (i);
    print ('\n');
}

def println (I, T...) (i : I, next : T) {
    print (i);
    print (expand (next));
    print ('\n');
}

def println (I, T...) (const i : I, const next : T) {
    print (i);
    print (expand (next));
    print ('\n');
}

def println (I, T...) (i : I, const next : T) {
    print (i);
    print (expand (next));
    print ('\n');
}

def print (I, T...) (i : I, nexts : T) {
    print (i);
    print (expand (nexts));
}

def print (I, T...) (i : I, const nexts : T) {
    print (i);
    print (expand (nexts));
}

def print (I, T...) (const i : I, const nexts : T) {
    print (i);
    print (expand (nexts));
}

def println (T...) (f : float, i : T) {
    print (f, i);
    print ('\n');
}

def printf (T...) (const str : string, nexts : T) {
    printf (str.ptr, expand (nexts));
}

def printfln (T...) (const str : string, nexts : T) {
    printf (str.ptr, expand (nexts));
    putchar ('\n');
}

def print if (is (T : tuple)) (T) (a : T) {
    import std.conv;
    print ("(");
    print (a.to!string);
    print (")");
}
