gen-verstrs.pl revision 662de5e1
1#!/usr/bin/env perl
2#
3# Generate C file that contains version strings
4
5($header        # This is lsquic.h that contains version enum which we parse
6    , $outfile  # This is destination C file
7    ) = @ARGV;
8
9open HEADER, $header
10    or die "cannot open $header for reading: $!";
11open OUT, ">$outfile"
12    or die "cannot open $outfile for writing: $!";
13
14while (<HEADER>) {
15    if (/^enum lsquic_version$/ .. /^}/) {
16        if (/^\s*(LSQVER_0*(\d+)),\s*$/ && $1 ne 'LSQVER_098') {
17            push @enums, $1;
18            push @versions, $2;
19            push @all_versions, $1;
20            push @all_alpns, "h3-Q0$2";
21        }
22        if (/^\s*(LSQVER_ID(\d+))\b/) {
23            push @draft_versions, $2;
24            push @all_versions, $1;
25            push @all_alpns, "h3-$2";
26        }
27    }
28}
29
30close HEADER;
31
32$timestamp = localtime;
33
34print OUT <<C_CODE;
35/*
36 * Auto-generated by $0 on $timestamp
37 */
38
39#include <assert.h>
40#include <string.h>
41
42#include "lsquic.h"
43
44struct lsquic_engine;
45
46static const char *const versions_to_string[ 1 << N_LSQVER ] = {
47C_CODE
48
49$max_mask = (1 << @versions) - 1;
50
51for ($mask = 0; $mask <= $max_mask; ++$mask) {
52    my @indexes;
53    for ($i = 0; $i < @versions; ++$i) {
54        if ($mask & (1 << $i)) {
55            push @indexes, $i;
56        }
57    }
58    print OUT "    [",
59        join('|', map "(1<<$_)", @enums[@indexes]) || 0,
60        "] = \"",
61        join(',', @versions[@indexes]),
62        "\",\n";
63}
64
65$enums = join '|', map "(1<<$_)", sort @enums;
66
67print OUT <<"C_CODE";
68};
69
70
71const char *
72lsquic_get_alt_svc_versions (unsigned versions)
73{
74    /* Limit to versions in versions_to_string: */
75    versions &= ($enums);
76    return versions_to_string[ versions ];
77}
78
79C_CODE
80
81
82$all_version_count_and_null = scalar(@all_versions) + 1;
83
84print OUT <<"C_CODE";
85static const struct {
86    unsigned    versions;
87    const char *h3_alpns[$all_version_count_and_null];
88} vers_2_h3_alnps[] = {
89    { 0, { NULL }},
90C_CODE
91
92for ($i = 0; $i < (1 << @all_versions); ++$i)
93{
94    my (@vers, @alpns);
95    for ($j = 0; $j < @all_versions; ++$j)
96    {
97        if ($i & (1 << $j))
98        {
99            push @vers, $all_versions[$j];
100            push @alpns, $all_alpns[$j];
101        }
102    }
103    if (@vers) {
104        print OUT "    {", join("|", map "(1<<$_)", @vers), ", ",
105            "{ ", join(", ", (map qq("$_"), @alpns), "NULL"), " }},\n";
106    }
107}
108
109$all_versions = join "|", map "(1<<$_)", @all_versions;
110
111print OUT <<"C_CODE";
112};
113
114const char *const *
115lsquic_get_h3_alpns (unsigned versions)
116{
117    unsigned i;
118
119    versions &= ($all_versions);
120
121    for (i = 0; i < sizeof(vers_2_h3_alnps) / sizeof(vers_2_h3_alnps[0]); ++i)
122        if (versions == vers_2_h3_alnps[i].versions)
123            return vers_2_h3_alnps[i].h3_alpns;
124
125    assert(0);
126    return vers_2_h3_alnps[0].h3_alpns;
127}
128C_CODE
129
130
131print OUT <<'C_CODE';
132
133enum lsquic_version
134lsquic_alpn2ver (const char *alpn, size_t len)
135{
136    static const struct el {
137        size_t len;
138        char alpn[10];
139        enum lsquic_version version;
140    } map[] = {
141C_CODE
142
143for ($i = 0; $i < @versions; ++$i) {
144    print OUT "        {sizeof(\"h3-Q0$versions[$i]\")-1,\"h3-Q0$versions[$i]\", $enums[$i]},\n";
145}
146
147for ($i = 0; $i < @draft_versions; ++$i) {
148    print OUT "        {sizeof(\"h3-$draft_versions[$i]\")-1,\"h3-$draft_versions[$i]\", LSQVER_ID$draft_versions[$i]},\n";
149}
150
151print OUT <<'C_CODE';
152    };
153    const struct el *el;
154
155    if (alpn)
156        for (el = map; el < map + sizeof(map) / sizeof(map[0]); ++el)
157            if (el->len == len && 0 == strncmp(el->alpn, alpn, len))
158                return el->version;
159
160    return -1;
161}
162C_CODE
163
164close OUT;
165