#!/usr/bin/env perl
#
# Generate C file that contains version strings

($header        # This is lsquic.h that contains version enum which we parse
    , $outfile  # This is destination C file
    ) = @ARGV;

open HEADER, $header
    or die "cannot open $header for reading: $!";
open OUT, ">$outfile"
    or die "cannot open $outfile for writing: $!";

while (<HEADER>) {
    if (/^enum lsquic_version$/ .. /^}/) {
        if (/^\s*(LSQVER_0*(\d+)),\s*$/ && $1 ne 'LSQVER_098') {
            push @enums, $1;
            push @versions, $2;
        }
        if (/^\s*LSQVER_ID(\d+)\b/) {
            push @draft_versions, $1;
        }
    }
}

close HEADER;

$timestamp = localtime;

print OUT <<C_CODE;
/*
 * Auto-generated by $0 on $timestamp
 */

#include <assert.h>

#include "lsquic.h"

struct lsquic_engine;

static const char *const versions_to_string[ 1 << N_LSQVER ] = {
C_CODE

$max_mask = (1 << @versions) - 1;

for ($mask = 0; $mask <= $max_mask; ++$mask) {
    my @indexes;
    for ($i = 0; $i < @versions; ++$i) {
        if ($mask & (1 << $i)) {
            push @indexes, $i;
        }
    }
    print OUT "    [",
        join('|', map "(1<<$_)", @enums[@indexes]) || 0,
        "] = \"",
        join(',', @versions[@indexes]),
        "\",\n";
}

$enums = join '|', map "(1<<$_)", sort @enums;

print OUT <<"C_CODE";
};


const char *
lsquic_get_alt_svc_versions (unsigned versions)
{
    /* Limit to versions in versions_to_string: */
    versions &= ($enums);
    return versions_to_string[ versions ];
}

C_CODE


$draft_version_count = @draft_versions;
$draft_version_count_and_null = $draft_version_count + 1;

print OUT <<"C_CODE";
static const struct {
    unsigned    versions;
    const char *h3_alpns[$draft_version_count_and_null];
} vers_2_h3_alnps[] = {
C_CODE

for ($i = 0; $i < (1 << @draft_versions); ++$i)
{
    my @vers;
    for ($j = 0; $j < @draft_versions; ++$j)
    {
        if ($i & (1 << $j))
        {
            push @vers, $draft_versions[$j];
        }
    }
    print OUT "   {", join("|", 0, map "(1<<LSQVER_ID$_)", @vers), ", ",
        "{ ", join(", ", map "\"h3-$_\"", @vers), @vers ? ", " : "", "NULL }},\n";
}

$draft_versions = join("|", map "(1<<LSQVER_ID$_)", @draft_versions);

print OUT <<"C_CODE";
};

const char *const *
lsquic_get_h3_alpns (unsigned versions)
{
    unsigned i;

    versions &= $draft_versions;

    for (i = 0; i < sizeof(vers_2_h3_alnps) / sizeof(vers_2_h3_alnps[0]); ++i)
        if (versions == vers_2_h3_alnps[i].versions)
            return vers_2_h3_alnps[i].h3_alpns;

    assert(0);
    return vers_2_h3_alnps[0].h3_alpns;
}
C_CODE

close OUT;
