litespeed-quic/src/liblsquic/gen-verstrs.pl

169 lines
3.6 KiB
Perl
Executable File

#!/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') {
if ($2 < 50) {
push @enums, $1;
push @versions, $2;
}
push @all_versions, $1;
push @all_alpns, "h3-Q0$2";
}
if (/^\s*(LSQVER_ID(\d+))\b/) {
push @draft_versions, $2;
push @all_versions, $1;
push @all_alpns, "h3-$2";
}
if (/^\s*(LSQVER_I(\d{3}))\b/) {
push @all_versions, $1;
if (not grep 'h3' eq $_, @all_alpns) {
push @all_alpns, "h3";
}
}
}
}
close HEADER;
$timestamp = localtime;
print OUT <<C_CODE;
/*
* Auto-generated by $0 on $timestamp
*/
#include <assert.h>
#include <string.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
$all_version_count_and_null = scalar(@all_versions) + 1;
print OUT <<"C_CODE";
static const struct {
unsigned versions;
const char *h3_alpns[$all_version_count_and_null];
} vers_2_h3_alnps[] = {
{ 0, { NULL }},
C_CODE
for ($i = 0; $i < (1 << @all_versions); ++$i)
{
my (@vers, @alpns);
for ($j = 0; $j < @all_versions; ++$j)
{
if ($i & (1 << $j))
{
push @vers, $all_versions[$j];
push @alpns, $all_alpns[$j];
}
}
if (@vers) {
print OUT " {", join("|", map "(1<<$_)", @vers), ", ",
"{ ", join(", ", (map qq("$_"), @alpns), "NULL"), " }},\n";
}
}
$all_versions = join "|", map "(1<<$_)", @all_versions;
print OUT <<"C_CODE";
};
const char *const *
lsquic_get_h3_alpns (unsigned versions)
{
unsigned i;
versions &= ($all_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
print OUT <<'C_CODE';
enum lsquic_version
lsquic_alpn2ver (const char *alpn, size_t len)
{
static const struct el {
size_t len;
char alpn[10];
enum lsquic_version version;
} map[] = {
C_CODE
for ($i = 0; $i < @all_alpns; ++$i) {
print OUT " {sizeof(\"$all_alpns[$i]\")-1,\"$all_alpns[$i]\", $all_versions[$i]},\n";
}
print OUT <<'C_CODE';
};
const struct el *el;
if (alpn)
for (el = map; el < map + sizeof(map) / sizeof(map[0]); ++el)
if (el->len == len && 0 == strncmp(el->alpn, alpn, len))
return el->version;
return -1;
}
C_CODE
close OUT;