From f5bd5efea9340c39c673d999d419a97bb6a20990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Mon, 6 Nov 2023 23:53:00 +0100 Subject: Add working example. --- .gitignore | 3 +++ Makefile | 29 +++++++++++++++++++++++++++++ html.py | 30 ++++++++++++++++++++++++++++++ http.py | 35 +++++++++++++++++++++++++++++++++++ roff.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 154 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100755 html.py create mode 100755 http.py create mode 100644 roff.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..639a26d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.csv +*.json +*.7 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..515b9cd --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +.PHONY: all clean check + +# Can be replaced with 'wget' +HTTPGET = curl -O + +all: http.7 html.7 + +http-status-codes-1.csv: + $(HTTPGET) https://www.iana.org/assignments/http-status-codes/$@ + +field-names.csv: + $(HTTPGET) https://www.iana.org/assignments/http-fields/$@ + +entities.json: + $(HTTPGET) https://html.spec.whatwg.org/$@ + +http.7: http.py http-status-codes-1.csv field-names.csv + ./$< > $@ + +html.7: html.py entities.json + ./$< > $@ + +check: + -flake8 *.py + -mypy *.py + +# Downloaded files aren't removed to save on bandwidth +clean: + -rm *.7 diff --git a/html.py b/html.py new file mode 100755 index 0000000..f5240d2 --- /dev/null +++ b/html.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 + +import json +import unicodedata +from roff import ( + now, + roff_table, + section_heading, + title_heading, +) + +title_heading("HTML", 7, + footer_middle=f"{now():%Y-%m-%d}") + +with open('entities.json') as f: + data = json.load(f) + + +section_heading("entities") + + +roff_table([("Seq", "R"), + ("Char", "L"), + ("Formal Name", "L")], + ["code", "characters", "formal"], + [{"code": code, + "characters": data["characters"], + "formal": ", ".join(unicodedata.name(c, "[NONAME]") + for c in data["characters"])} + for (code, data) in data.items()]) diff --git a/http.py b/http.py new file mode 100755 index 0000000..946bd5f --- /dev/null +++ b/http.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 + +import csv +from roff import ( + now, + roff_table, + section_heading, + subsection_heading, + title_heading, +) +title_heading('HTTP', 7, + footer_middle=f"{now():%Y-%m-%d}") + +section_heading("STATUS CODES") + +with open('http-status-codes-1.csv') as f: + entries = list(csv.DictReader(f)) + +roff_table([("Code", 'R'), + ("Description", "L"), + ("Reference", 'L')], + ["Value", "Description", "Reference"], + entries) + +section_heading('HEADERS') + +with open("field-names.csv") as f: + entries = list(csv.DictReader(f)) + +for entry in entries: + subsection_heading(entry["Field Name"]) + print(entry["Status"] + ", ") + print(entry["Reference"]) + print() + print(entry["Comments"]) diff --git a/roff.py b/roff.py new file mode 100644 index 0000000..2690e2f --- /dev/null +++ b/roff.py @@ -0,0 +1,57 @@ +""" +Library for generating roff markup. + +This library is FAR from complete, and supports exactly what these +scripts require. + +For information about roff commands meaning, see groff_man(7). +""" + +import os +from datetime import datetime +from typing import TypeAlias, Literal + + +Align: TypeAlias = Literal['R', 'L'] + + +def title_heading(topic: str, + section: int, + *, + footer_middle: str | None = None, + footer_inside: str | None = None, + header_middle: str | None = None): + print(f'.TH "{topic.upper()}" {section} "{footer_middle}"') + + +def section_heading(s: str): + print(f'.SH "{s.upper()}"') + + +def subsection_heading(s: str): + print(f'.SS "{s}"') + + +def roff_table(headers: list[tuple[str, Align]], + keys: list[str], + entries: list[dict[str, str]]): + print(".TS") + print("tab(@);") + print(' '.join([a for (_, a) in headers] + ['.'])) + + print("@".join(h for (h, _) in headers)) + + for entry in entries: + print("@".join(entry[key] for key in keys)) + + print(".TE") + + +def now(): + if ct := os.getenv("CURRENT_TIME"): + if ct.isnumeric(): + return datetime.fromtimestamp(int(ct)) + else: + return datetime.fromisoformat(ct) + else: + return datetime.now() -- cgit v1.2.3