#!perl

use strict;
use warnings;

print <<'EOF';

#ifndef MOCK_TABLE_HEADER
#define MOCK_TABLE_HEADER

/* DO NOT EDIT THIS FILE */
/* auto-generated by build_mock_table.pl */

#define MOCK_VA_NUM_ARGS(...) MOCK_VA_NUM_ARGS_IMPL_((__VA_ARGS__,    63, 62, 61, 60, \
                                    59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \
                                    49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \
                                    39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \
                                    29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \
                                    19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \
                                     9,  8,  7,  6,  5,  4,  3,  2,  1))
#define MOCK_VA_NUM_ARGS_IMPL_(tuple) MOCK_VA_NUM_ARGS_IMPL tuple

#define MOCK_VA_NUM_ARGS_IMPL( \
                      _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
                     _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
                     _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
                     _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
                     _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
                     _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
                     _61,_62,_63,N,...) N


#define MOCK_macro_dispatcher(func, ...)   MOCK_macro_dispatcher_(func, MOCK_VA_NUM_ARGS(__VA_ARGS__))

// the three levels of indirection are a work-around for broken variadic macro support in Visual C++
#define MOCK_macro_dispatcher_(func, nargs)           MOCK_macro_dispatcher__(func, nargs)
#define MOCK_macro_dispatcher__(func, nargs)           MOCK_macro_dispatcher___(func, nargs)
#define MOCK_macro_dispatcher___(func, nargs)          func ## nargs

#define PP_NARG(...) MOCK_macro_dispatcher(mock, __VA_ARGS__)

//mock1 works for 1 or 0
#define mock1(test_reporter, function_name, mock_file, mock_line, arguments_string, ...)\
  mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, __VA_ARGS__)

EOF

my @macros;
my @mocks = ("mock_", "mock_");

for my $i (2 .. 63) {
    push(@mocks, sprintf("mock%d", $i));
    push(@macros, define_mock($i));
}

my @reverse_mocks = reverse(@mocks);

my @chunk;
print "#define PP_RSEQ_N() \\\n";
while (@chunk = splice(@reverse_mocks, 0, 10)) {
    print "\t";
    print join(", ", @chunk);
    if (@reverse_mocks) {
        print ",\\\n";
    }
    else {
        print "\n";
    }
}

print "\n";
print join("\n", @macros);
print "\n";
print "#endif /* MOCK_TABLE_HEADER */\n";

sub define_mock {
    my ($num_args) = @_;

    my @args;
    my $i;
    for ($i = 0; $i < $num_args; $i++) {
        push(@args, sprintf "arg%d", $i);
    }

    my $macro = sprintf("#define mock%d", $num_args);
    $macro .= "(test_reporter, function_name, mock_file, mock_line, arguments_string, ";
    $macro .= join(", ", @args);
    $macro .= ")\\\n";
    $macro .= "  mock_(test_reporter, function_name, mock_file, mock_line, arguments_string, ";
    $macro .= join(", ", (map "(intptr_t) $_", @args));
    $macro .= ")\n";

    return $macro;
}

