Source code
Revision control
Copy as Markdown
Other Tools
#!/usr/bin/env python
import io
import pathlib
from collections import defaultdict
import multidict
ROOT = pathlib.Path.cwd()
while ROOT.parent != ROOT and not (ROOT / "pyproject.toml").exists():
ROOT = ROOT.parent
def calc_headers(root):
hdrs_file = root / "aiohttp/hdrs.py"
code = compile(hdrs_file.read_text(), str(hdrs_file), "exec")
globs = {}
exec(code, globs)
headers = [val for val in globs.values() if isinstance(val, multidict.istr)]
return sorted(headers)
headers = calc_headers(ROOT)
def factory():
return defaultdict(factory)
TERMINAL = object()
def build(headers):
dct = defaultdict(factory)
for hdr in headers:
d = dct
for ch in hdr:
d = d[ch]
d[TERMINAL] = hdr
return dct
dct = build(headers)
HEADER = """\
/* The file is autogenerated from aiohttp/hdrs.py
Run ./tools/gen.py to update it after the origin changing. */
#include "_find_header.h"
#define NEXT_CHAR() \\
{ \\
count++; \\
if (count == size) { \\
/* end of search */ \\
return -1; \\
} \\
pchar++; \\
ch = *pchar; \\
last = (count == size -1); \\
} while(0);
int
find_header(const char *str, int size)
{
char *pchar = str;
int last;
char ch;
int count = -1;
pchar--;
"""
BLOCK = """
{label}
NEXT_CHAR();
switch (ch) {{
{cases}
default:
return -1;
}}
"""
CASE = """\
case '{char}':
if (last) {{
return {index};
}}
goto {next};"""
FOOTER = """
{missing}
missing:
/* nothing found */
return -1;
}}
"""
def gen_prefix(prefix, k):
if k == "-":
return prefix + "_"
else:
return prefix + k.upper()
def gen_block(dct, prefix, used_blocks, missing, out):
cases = {}
for k, v in dct.items():
if k is TERMINAL:
continue
next_prefix = gen_prefix(prefix, k)
term = v.get(TERMINAL)
if term is not None:
index = headers.index(term)
else:
index = -1
hi = k.upper()
lo = k.lower()
case = CASE.format(char=hi, index=index, next=next_prefix)
cases[hi] = case
if lo != hi:
case = CASE.format(char=lo, index=index, next=next_prefix)
cases[lo] = case
label = prefix + ":" if prefix else ""
if cases:
block = BLOCK.format(label=label, cases="\n".join(cases.values()))
out.write(block)
else:
missing.add(label)
for k, v in dct.items():
if not isinstance(v, defaultdict):
continue
block_name = gen_prefix(prefix, k)
if block_name in used_blocks:
continue
used_blocks.add(block_name)
gen_block(v, block_name, used_blocks, missing, out)
def gen(dct):
out = io.StringIO()
out.write(HEADER)
missing = set()
gen_block(dct, "", set(), missing, out)
missing_labels = "\n".join(m for m in sorted(missing))
out.write(FOOTER.format(missing=missing_labels))
return out
def gen_headers(headers):
out = io.StringIO()
out.write("# The file is autogenerated from aiohttp/hdrs.py\n")
out.write("# Run ./tools/gen.py to update it after the origin changing.")
out.write("\n\n")
out.write("from . import hdrs\n")
out.write("cdef tuple headers = (\n")
for hdr in headers:
out.write(" hdrs.{},\n".format(hdr.upper().replace("-", "_")))
out.write(")\n")
return out
# print(gen(dct).getvalue())
# print(gen_headers(headers).getvalue())
folder = ROOT / "aiohttp"
with (folder / "_find_header.c").open("w") as f:
f.write(gen(dct).getvalue())
with (folder / "_headers.pxi").open("w") as f:
f.write(gen_headers(headers).getvalue())