diff --git a/Makefile b/Makefile index af44ac1c..0a18b4eb 100644 --- a/Makefile +++ b/Makefile @@ -620,6 +620,10 @@ $(SORTIX_RELEASE_DIR)/$(RELEASE)/README: README $(SORTIX_RELEASE_DIR)/$(RELEASE) .PHONY: release-man release-man: $(SORTIX_RELEASE_DIR)/$(RELEASE)/man/ports.list +.PHONY: release-man-html +release-man-html: release-man + RELEASE="$(RELEASE)" build-aux/manhtml.sh $(SORTIX_RELEASE_DIR)/$(RELEASE)/man + .PHONY: release-readme release-readme: $(SORTIX_RELEASE_DIR)/$(RELEASE)/README @@ -627,12 +631,12 @@ release-readme: $(SORTIX_RELEASE_DIR)/$(RELEASE)/README release-arch: release-builds release-readme release-repository .PHONY: release-shared -release-shared: release-man release-readme release-scripts +release-shared: release-man release-man-html release-readme release-scripts .PHONY: release release: release-arch release-shared cd $(SORTIX_RELEASE_DIR)/$(RELEASE) && \ - find . -type f '!' -name sha256sum -exec sha256sum '{}' ';' | \ + find . -type f '!' -name sha256sum '!' -name '*.html' -exec sha256sum '{}' ';' | \ sed -E 's,^([^ ]* )\./,\1,' | \ LC_ALL=C sort -k 2 > sha256sum diff --git a/build-aux/footer.html b/build-aux/footer.html new file mode 100644 index 00000000..aa764c26 --- /dev/null +++ b/build-aux/footer.html @@ -0,0 +1,3 @@ + + + diff --git a/build-aux/header.html b/build-aux/header.html new file mode 100644 index 00000000..01faaf00 --- /dev/null +++ b/build-aux/header.html @@ -0,0 +1,9 @@ + + + + + + @title@ + + +
diff --git a/build-aux/manhtml.sh b/build-aux/manhtml.sh new file mode 100755 index 00000000..407e3d8f --- /dev/null +++ b/build-aux/manhtml.sh @@ -0,0 +1,398 @@ +#!/bin/sh +set -e + +export LC_ALL=C +SECTIONS="1 2 3 4 5 6 7 8 9" +if [ -z ${SORTIX_SITE_OFFICIAL+x} ]; then + SORTIX_SITE_OFFICIAL="https://sortix.org/" +fi +if [ -z ${SORTIX_RELEASE_SITE+x} ]; then + SORTIX_RELEASE_SITE="https://pub.sortix.org/sortix/release" +fi +if [ -z ${MANHTML_TO_SITE_ROOT+x} ]; then + MANHTML_TO_SITE_ROOT=. +fi +if [ -z ${MANHTML_TEMPLATE+x} ]; then + MANHTML_TEMPLATE="$(dirname -- "$(realpath -- "$(which -- "$0")")")" +fi +if [ -z ${MANHTML_RELEASES+x} ]; then + MANHTML_RELEASES="current nightly" +fi +if [ -z ${RELEASE+x} ]; then + RELEASE="current" +fi +if [ -z ${RELEASE_STRING+x} ]; then + if [ "$RELEASE" = current ]; then + RELEASE_STRING="Sortix" + else + RELEASE_STRING="Sortix $RELEASE" + fi +fi + +if [ $# -lt 1 ]; then + echo "Usage: $0 mandir $#" >&2 + exit 1 +fi + +if [ ! -e "$1/ports.list" ]; then + echo "$0: No ports.list in $1" >&2 + exit 1 +fi + +cd "$1" + +backwards() { + echo "$1" | tr -cd / | sed 's,/,../,g' +} + +tositeofficial() { + BACKWARDS=$(backwards "$1") + case "$SORTIX_SITE_OFFICIAL" in + http*) echo "$SORTIX_SITE_OFFICIAL" ;; + *) echo "$BACKWARDS$SORTIX_SITE_OFFICIAL" ;; + esac +} + +tositeroot() { + echo "$(backwards "$1")$MANHTML_TO_SITE_ROOT" +} + +frontpage() { + tositeofficial "$1" | sed 's/^$/./g' +} + +begin_html() { + cat "$MANHTML_TEMPLATE/header.html" | sed "s|@title@|$1|g" +} + +header() { + cat << EOF +

$1

+EOF +} + +section() { + cat << EOF +

$1

+EOF +} + +bp() { + echo "

" +} + +ep() { + echo "

" +} + +link() { + cat << EOF +$2$3
+EOF +} + +end_html() { + cat "$MANHTML_TEMPLATE/footer.html" +} + +finalize_html_stdout() { + sed -e "s,@root@,$(tositeroot "$1"),g" \ + -e "s,@official@,$(tositeofficial "$1"),g" \ + -e "s,@frontpage@,$(frontpage "$1"),g" \ + -e "s,@year@,$(date +%Y),g" +} + +finalize_html() { + if [ "$VERBOSE" = 1 ]; then + echo "$1" >&2 + fi + finalize_html_stdout "$1" > "$1" +} + +section_name() { + case "$1" in + 1) echo "General Commands Manual";; + 2) echo "System Calls Manual";; + 3) echo "Library Functions Manual";; + 4) echo "Device Drivers Manual";; + 5) echo "File Formats Manual";; + 6) echo "Games Manual";; + 7) echo "Miscellaneous Information Manual";; + 8) echo "System Manager's Manual";; + 9) echo "Kernel Developer's Manual";; + esac +} + +# TODO: This doesn't work for headers in manual pages like addr2line(1) that +# doesn't use mdoc(7), so the sections don't have id attributes. +selflink() { + python3 -c ' +import re +import sys + +id_map = {} +first_pass = [] +for line in sys.stdin.readlines(): + result = "" + while True: + match = re.search("(.*?)]*)\")?>(.*?)(.*)", line, flags=re.DOTALL) + if match is None: + result += line + break + lead = match.group(1) + hl = match.group(2) + oldid = match.group(4) + h = match.group(5) + rest = match.group(6) + id = h.lower().replace(" ", "-").replace("%", "%25"); + if oldid is not None: + id_map[oldid] = id + result += lead + "" + h + "" + line = rest + first_pass.append(result) +for line in first_pass: + result = "" + while True: + match = re.search("(.*?)]*)\">(.*?)(.*)", line, flags=re.DOTALL) + if match is None: + result += line + break + lead = match.group(1) + id = match.group(2) + text = match.group(3) + rest = match.group(4) + if id in id_map: + id = id_map[id] + result += lead + "" + text + "" + line = rest + print(result, end="") +' +} + +see_other_releases() { + if [ "$2" = true ]; then + echo '
' + else + bp + echo "View in release:" + fi + for OTHER_RELEASE in $MANHTML_RELEASES; do + if [ "$RELEASE" = "$OTHER_RELEASE" ]; then + OTHER_RELEASE_URL=$(backwards "$1")"$1" + elif [ "$OTHER_RELEASE" = current ]; then + OTHER_RELEASE_URL=$(tositeofficial "$1")"man/$1" + elif echo "$OTHER_RELEASE" | grep -Eq '^[0-9]+.[0-9]+$'; then + OTHER_RELEASE_URL=$(tositeofficial "$1")"release/$OTHER_RELEASE/man/$1" + else + OTHER_RELEASE_URL="$SORTIX_RELEASE_SITE/$OTHER_RELEASE/man/$1" + fi + if [ "$OTHER_RELEASE" = "$RELEASE" ]; then + printf ' %s' "$OTHER_RELEASE_URL" "$OTHER_RELEASE" + else + printf ' %s' "$OTHER_RELEASE_URL" "$OTHER_RELEASE" + fi + done + if [ "$2" = true ]; then + echo '
' + else + ep + fi +} + +see_stable() { + if [ "$2" = true ]; then + see_other_releases "$@" + fi + case "$RELEASE" in + current) + if [ "$2" != true ]; then + see_other_releases "$@" + fi + ;; + *dev* | nightly | volatile) + if [ "$2" = true ]; then + header "$RELEASE_STRING manual" + else + see_other_releases "$@" + fi + bp + cat << EOF +This manual documents $RELEASE_STRING, a development build that has not +been officially released. You can instead view +this document in the latest official manual. +EOF + ep + ;; + *) + if [ "$2" = true ]; then + header "$RELEASE_STRING manual" + else + see_other_releases "$@" + fi + bp + cat << EOF +This manual documents $RELEASE_STRING. You can instead view +this document in the latest official manual. +EOF + ep + ;; + esac +} + +undocumented_see_also() { + (cat && echo "../man1/man.1.html") | + sort | + (while read FILE; do + NAME=$(expr x"$FILE" : x'.*/\([^/]*\)\.[0-9]\.html$') + SECTION=$(expr x"$FILE" : x'.*\.\([0-9]\)\.html$') + printf ".Xr $NAME $SECTION /" + done) | sed -e 's| /$|\\|' -e 's|/|,\\|g' | tr '/' ',' | tr '\\' '\n' +} + +echo "Generating manhtml index" +(begin_html "$RELEASE_STRING manual page index" + header "$RELEASE_STRING manual page index" + see_stable "" + section "Introductory manual pages" "introductory" + bp + link "man7/installation.7.html" "installation(7)" + link "man7/upgrade.7.html" "upgrade(7)" + link "man7/user-guide.7.html" "user-guide(7)" + link "man7/development.7.html" "development(7)" + link "man7/cross-development.7.html" "cross-development(7)" + if [ -f "man7/following-development.7" ]; then + link "man7/following-development.7.html" "following-development(7)" + fi + if [ -f "man7/porting.7" ]; then + link "man7/porting.7.html" "porting(7)" + fi + ep + section "Sortix manual pages" "system" + bp + link "system.html" "System manual pages" + for section in $SECTIONS; do + link "system.html#$section" "System Section $section - $(section_name $section)" + done + section "All manual pages" "all" + link "all.html" "All manual pages" + for section in $SECTIONS; do + link "man$section/" "Section $section - $(section_name $section)" + done + ep + section "Ports manual pages" "ports" + bp + cat ports.list | sort | + while read port; do + if [ -s "$port.list" ]; then + link "$port.html" "$port" + else + link "$port.html" "$port" " (no manual pages)" + fi + done + ep + end_html) | finalize_html index.html + +(echo system && cat ports.list) | +while read port; do + echo "Generating manhtml index for $port" + (if [ "$port" = system ]; then prettyport="System"; else prettyport=$port; fi + begin_html "$prettyport manual pages" && + header "$prettyport manual pages" && + see_stable "$port.html" + section_not_begun=true + for section in $SECTIONS; do + section_not_begun=true + mkdir -p "man$section" + grep -E "^/share/man/man$section/.*\.$section$" "$port.list" | sort | + while read manpage; do + if $section_not_begun; then + section "Section $section - $(section_name $section)" "$section" + bp + section_not_begun=false + fi + manpage=$(basename -- "$manpage") + name=$(echo "$manpage" | sed "s/\.$section$//") + link "man$section/$manpage.html" "$name($section)" + if [ "x$port" = xsystem ]; then + mandoc -Tlint "man$section/$manpage" 1>&2 || true + fi + done + if ! $section_not_begun; then + ep + fi + done + if [ ! -s "$port.list" ]; then + echo "

$prettyport contains no manual pages.

" + fi + end_html) | finalize_html $port.html +done + +for section in $SECTIONS; do + echo "Generating manhtml index for section $section" + mkdir -p "man$section" + (begin_html "Section $section - $(section_name $section)" && + header "Section $section - $(section_name $section)" && + see_stable "man$section/" + ls man$section | sort | grep -E "\.$section$" | + while read manpage; do + manpage=$(basename -- "$manpage") + name=$(echo "$manpage" | sed "s/\.$section$//") + link "$manpage.html" "$name($section)" + done + if ! ls man$section | grep -Eq "\.$section$"; then + echo "

Section $section contains no manual pages.

" + fi + end_html) | finalize_html man$section/index.html +done + +for section in $SECTIONS; do + find man$section -type f | sort | grep -E "\.$section$" | + while read manpage; do + filename=$(basename -- "$manpage") + name=$(expr "x$filename" : 'x\(.*\)\.[^.]*') + echo Generating manhtml $manpage + (begin_html "$name($section)" + see_stable "$manpage.html" true + mandoc -Thtml -Ofragment,man=../man%S/%N.%S.html "$manpage" | selflink + end_html) | finalize_html "$manpage.html" + done +done + +(find . -name '*.html' | while read FILE; do + grep -Eoh 'href=\"../man[[:digit:]]/[^/]+\.html\"' "$FILE" || true + done) | sort -u | grep -Eo 'man[[:digit:]]/[^/]+\.html' | sed 's/\.html$//' | +while read manpage; do + if ! [ -e "$manpage" ]; then + echo "Generating undocumented manhtml for $manpage" + filename=$(basename -- "$manpage") + name=$(expr "x$filename" : 'x\(.*\)\.[^.]*') + NAME=$(echo "$filename" | tr '[:lower:]' '[:upper:]') + section=$(expr "x$manpage" : 'x.*\.\([^.]*\)') + (begin_html "$name($section)" + see_stable "$manpage.html" true + (cat man7/undocumented.7 | + grep -Ev '^\.Xr man 1$' | + sed -e "s/UNDOCUMENTED/$NAME/g" -e "s/undocumented/$name/g" && + grep -rl -F -- "../$manpage.html" . | + grep -E '\.html$' | + undocumented_see_also) | + mandoc -Thtml -Oman=../man%S/%N.%S.html | selflink + end_html) | finalize_html "$manpage.html" + fi +done + +echo "Generating manhtml index for all" +(begin_html "All manual pages for Sortix" + header "All manual pages for Sortix" + see_stable "all.html" + for section in $SECTIONS; do + section "Section $section" "$section" + bp + ls man$section | sort | grep -E "\.$section$" | + while read manpage; do + name=$(echo "$manpage" | sed "s/\.$section$//") + link "man$section/$manpage.html" "$name($section)" + done + ep + done + end_html) | finalize_html all.html diff --git a/build-aux/ports.conf b/build-aux/ports.conf index 0b974251..c22e6c45 100644 --- a/build-aux/ports.conf +++ b/build-aux/ports.conf @@ -1,3 +1,3 @@ set_minimal="cut dash e2fsprogs grep grub mdocml sed xargs" -set_basic="$set_minimal binutils bison bzip2 diffutils ed flex gawk gcc git gzip libcurses libstdc++ nano make patch pkg-config tar vim xz xorriso" +set_basic="$set_minimal binutils bison bzip2 diffutils ed flex gawk gcc git gzip libcurses libstdc++ nano make patch pkg-config python tar vim xz xorriso" sets="basic minimal" diff --git a/share/man/man7/cross-development.7 b/share/man/man7/cross-development.7 index ab4805d6..a730aa9c 100644 --- a/share/man/man7/cross-development.7 +++ b/share/man/man7/cross-development.7 @@ -34,6 +34,8 @@ GRUB (for iso creation) xorriso (for iso creation) .It mtools (for iso creation) (if on UEFI systems) +.It +mandoc (for html manuals if building a release directory) .El .Pp GRUB with BIOS support is required.