Knowledge Base

Preserving for the future: Shell scripts, AoC, and more

txt2man wrapper which adds man page headings support in text file

txt2man is great. It depends on only GNU awk, which I can certainly live with. I previously used go-md2man which is also fine, but I just don't want to depend on golang. txt2man has an area where I wanted to improve it, but I didn't know how to contribute to upstream in a way that I expect they would want. So I wrote txt2man-wrapper! Txt2man adds the page titles, section number, etc., from parameters on the command line invocation, but I wanted to add the ability to store these values in the text file.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/bin/sh
# File: txt2man-wrapper
# Location: /usr/bin
# License: CC-BY-SA 4.0
# Author: bgstack15
# Startdate: 2020-04-15 17:35
# Title: Txt2man wrapper that adds title headings support
# Purpose: add title headings support to txt2man
# History:
# Usage:
# Custom layout for input text file, where first lines include "section 3", "title txt2man-wrapper", "project bgscripts", "volume Linux command reference" in no particular order, followed by "====="
# Reference:
# txt2man
# Improve:
# Dependencies:
# dep-raw: /usr/bin/awk, /usr/bin/txt2man
# rec-devuan: gawk | mawk, txt2man
# rec-fedora: coreutils, txt2man
test -z "${INFILE}" && test -n "${1}" && export INFILE="${1}"
if test -z "${INFILE}" || test "${INFILE}" = "-" ; then USE_STDIN=1 ; fi

if test "${USE_STDIN}" = "1" ;
then
input="$( cat )"
else
input="$( cat "${INFILE}" )"
fi

head="$( echo "${input}" | awk 'BEGIN{a=0} /^=====/{a=1} {if(a==0)print}' )"
short="$( echo "${input}" | awk '{if(a)print} /^=====/{a=1}' )"

ul="$( echo "${head}" | awk '$1=="title" {$1="";print}' | sed -r -e 's/^\s*//;' )"
uln="$( echo "${head}" | awk '$1=="section" {$1="";print}' | sed -r -e 's/^\s*//;' )"
dc="$( echo "${head}" | awk '$1=="date" {$1="";print}' | sed -r -e 's/^\s*//;' )"
ur="$( echo "${head}" | awk '$1=="project" {$1="";print}' | sed -r -e 's/^\s*//;' )"
uc="$( echo "${head}" | awk '$1=="volume" {$1="";print}' | sed -r -e 's/^\s*//;' )"
bolds1="$( echo '`__xxNONExx__`' "${short}" | tr -d '\r\n' | tr '`' '\n' | awk 'NR/2==int(NR/2){print}' | xargs -n1 printf '%s %s ' '-B' )"
bolds2="$( echo "*__xxNANExx__*" "${short}" | tr -d '\r\n' | tr '*' '\n' | awk 'NR/2==int(NR/2){print}' | xargs -n1 printf '%s %s ' '-B' )"
ital1="$( echo "${short}" "**__xxNBNExx__**" | tr -d '\r\n' | sed -r -e 's/\*\*/\n/g;' | awk 'NR/2==int(NR/2){print}' | xargs -n1 printf '%s %s ' '-I' )"
test -n "${DEBUG}" && echo "${bolds1}" "${bolds2}" "${ital1}" 1>&2
echo "${short}" | txt2man -t "${ul}" -r "${ur}" -s "${uln}" -v "${uc}" -d "${dc}" ${bolds1} ${bolds2} ${ital1}

Using my handy txt2man-wrapper above, or found in my bgscripts package, you can have a text file suitable for txt2man, with some extra header lines at the top.

title sizer
section 1
project bgscripts-core
volume General Commands Manual
date April 2020
=====
NAME
  sizer - summarize directory contents by file extension

And invoke txt2man-wrapper like so:

txt2man-wrapper < sizer.1.txt | gzip > sizer.1.gz

In a Makefile, you can use something similar to:

MAN_TXT:=$(wildcard usr/share/man/man*/*.txt)
MAN_GZ:= $(subst .txt,.gz,$(MAN_TXT))

build_man: $(MAN_GZ)

$(MAN_GZ): %.gz: %.txt
   txt2man-wrapper - < $< | ${gzipbin} > $@

Comments