#!/usr/bin/env python3 """Compile the exact PickleBuffer buffer table as C89 and check both slots.""" import re import subprocess import sys import tempfile from pathlib import Path source_path = Path(sys.argv[1]) source = source_path.read_text() match = re.search(r"static PyBufferProcs picklebuf_as_buffer = \{.*?\n\};", source, re.S) assert match, "picklebuf_as_buffer initializer not found" header = (source_path.parent.parent / "Include/cpython/object.h").read_text() layout = re.search(r"typedef struct \{([^{}]*)\} PyBufferProcs;", header, re.S) assert layout, "PyBufferProcs layout not found" body = re.sub(r"/\*.*?\*/", "", layout.group(1), flags=re.S) assert re.findall(r"\b(bf_\w+)\s*;", body) == ["bf_getbuffer", "bf_releasebuffer"] harness = r''' #include typedef struct { int unused; } PyObject; typedef struct { int unused; } Py_buffer; typedef int (*getbufferproc)(PyObject *, Py_buffer *, int); typedef void (*releasebufferproc)(PyObject *, Py_buffer *); static int picklebuf_getbuf(PyObject *self, Py_buffer *view, int flags) { (void)self; (void)view; return flags; } static void picklebuf_releasebuf(PyObject *self, Py_buffer *view) { (void)self; (void)view; } ''' harness += "typedef struct {" + body + "} PyBufferProcs;\n" harness += match.group(0) harness += r''' int main(void) { assert(picklebuf_as_buffer.bf_getbuffer == (getbufferproc)picklebuf_getbuf); assert(picklebuf_as_buffer.bf_releasebuffer == (releasebufferproc)picklebuf_releasebuf); return 0; } ''' with tempfile.TemporaryDirectory(prefix="vc6-picklebuf-buffer-") as directory: path = Path(directory) (path / "test.c").write_text(harness) result = subprocess.run([ "cc", "-std=c89", "-pedantic-errors", "-Wall", "-Wextra", "-Werror", str(path / "test.c"), "-o", str(path / "test"), ]) if result.returncode: sys.exit(result.returncode) subprocess.run([str(path / "test")], check=True) print("picklebuf_as_buffer C89 compile and both semantic field mappings: PASS")