2 # Copyright © 2014 Géraud Meyer <graud@gmx.com>
4 # This program is free software; you can redistribute it and/or modify it under
5 # the terms of the GNU General Public License version 2 as published by the
6 # Free Software Foundation.
8 # This program is distributed in the hope that it will be useful, but WITHOUT
9 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 # You should have received a copy of the GNU General Public License along with
14 # this program. If not, see <http://www.gnu.org/licenses/>.
16 PROGRAM_NAME
="helpm2pod"
18 # valid help text example
22 $PROGRAM_NAME - convert a specially formatted help text to POD
25 $PROGRAM_NAME [<options>] [--] [<file> [<name>.<section>[.<helpm>]]]
27 $PROGRAM_NAME converts a HelpMessage to POD. The text is
read from the
28 given
<file> or from standard input
if a dash
(-) or nothing is given.
30 It can also further process the POD document with pod2man
(1) to obtain a
31 man
(7) document. In that
case the filename is used to guess the section
32 and the manual name. An additional optional argument allows to override
33 the filename used
for that purpose or to give one
if the standard input is
36 See helpmessage
(5) for a description of the HelpMessage format.
38 The programs helpm4sh
(1) and gitparseopt2helpm
(1) can be used to obtain a
41 The options are parsed by getopt
(1).
43 Print a
help message and
exit.
45 Convert the HelpMessage to POD
; this is the default.
47 Convert the HelpMessage to man
(7). If stdout is a tty
, view the
50 If invalid lines are detected
, 1 is returned. If there are no errors
, 0 is
53 To convert the
help output of this program to a manual page
:
54 $ helpm2pod
-h |helpm2pod |pod2man
-n HELPM2POD
>helpm2pod
.1
55 To view the same manual
in the pager
:
56 $ helpm2pod
-h |helpm2pod
--man - HELPM2POD
58 helpm2pod was written by G.raud Meyer.
60 helpmessage
(5), perlpod
(1), pod2man
(1), man
(7), helpm2text
(1)
64 # command line parsing
66 GETOPT_LOPT
=help,help-man
,pod
,man
,version
67 if getopt
-T >/dev
/null
68 then CL
=`getopt $GETOPT_OPT $*`
69 else CL
=`getopt -o $GETOPT_OPT -l $GETOPT_LOPT -- "$@"`
72 then echo >&2 "$PROGRAM_NAME: syntax error"; exit 255
74 if getopt
-T >/dev
/null
76 else eval set -- "$CL"
82 --help|
-h) help_message
; exit 0 ;;
83 --help-man) "$0" -h |
"$0" --man -; exit ;;
86 --version|
-V) echo "$PROGRAM_NAME version $PROGRAM_VERSION"; exit ;;
93 then echo >&2 "$PROGRAM_NAME: error: too many arguments"; exit 255
95 [ $# -gt 0 ] ||
set -- -
96 if [ $# -gt 0 ] && expr "$1" : '[a-zA-Z_][a-zA-Z_0-9]*=' >/dev
/null
100 [ $# -ge 2 ] && FILE
=$2
101 # attempt to guess the manual name and the section from the first filename
104 FILE
=${FILE##*/}; SECTION
=${FILE##*.}
105 if [ x
"$SECTION" = x
"$FILE" ]
107 SECTION
= # no section/extension found
110 expr "$SECTION" : '[Hh]\([Ee][Ll][Pp]\)\{0,1\}[Mm]\(essage\)\{0,1\}' >/dev
/null ||
111 expr "$SECTION" : '[Tt][Ee]\{0,1\}[Xx][Tt]' >/dev
/null
113 FILE
=${FILE%."$SECTION"} # get rid of the extension
115 if [ x
"$SECTION" = x
"$FILE" ]
117 SECTION
= # no section found
120 if expr x
"$SECTION" : x
'[0-9][a-zA-Z]\{0,\}' >/dev
/null
122 FILE
=${FILE%."$SECTION"} # get rid of the section
127 [ x
"$FILE" = x
"-" ] && FILE
=
131 # section is set to the type:
132 # - use: synopsis, name have one synopsis per line
133 # - opt: options which is a list with additional formatting
134 # - def: default for other sections
135 awk -v PROGRAM_NAME
="$PROGRAM_NAME" 'BEGIN { ORS="" }
137 FNR == 1 && $0 ~ /^[# ]|^\/\// { next }
142 if (_sep < n) _sep=n; if (n < 0 && _sep < -n) _sep=-n
143 # do print the blank lines and reset the counter
145 while (_blank-- > 0) { _sep--; print "\n" }; _blank=0
146 while (_sep-- > 0) print "\n"; _sep=0
150 function line(arg) { sep(0); print(arg "\n") }
151 function sline(arg) { sep(-1); print(arg "\n"); sep(1) }
153 !/^( *|\t)\t/ && list { list=0; sline("=back") }
154 # input blank lines are kept
155 /(^|^\t)$/ { _blank++; next } # remember spacing blank lines
156 # may be verbatim space or an invalid line
157 /^[ \t]*$/ { sub(/^\t/, ""); line($0); next }
160 sep(-2); print "=head1 "
161 if (tolower($1) ~ /^usage:?$|^synopsis/) { section="use"; print "SYNOPSIS" }
162 else if (tolower($1) ~ /^options/) { section="opt"; print "OPTIONS" }
163 else if (tolower($1) ~ /^[a-z]/) { section="def"; sub(/:$/,""); print toupper($0) }
164 print "\n"; sep(1); next
168 sep(2); sline("=head2 " $0); next
171 function style(l, cmd) {
172 cmd = "printf \"%s\\n\" " sqesc(l) "| LC_ALL=C sed -r" \
173 " -e '\''s/(^|[^A-Z])(<[_a-zA-Z0-9-]{1,}>)/\\1I\\2/g'\''" \
174 " -e '\''s/(^|[^a-zA-Z0-9_-])\\*([a-zA-Z0-9_-]{1,})\\*([^a-zA-Z0-9_-]|$)/\\1B<\\2>\\3/g'\''"
175 cmd | getline l; close(cmd)
178 function item(l, cmd) {
179 cmd = "printf \"%s\\\\n\" " sqesc(l) "| LC_ALL=C sed -r" \
180 " -e '\''s/(^|[^a-zA-Z])(<[_a-zA-Z0-9-]{1,}>)/\\1I\\2/g'\''"
181 if (section ~ /^opt/)
182 cmd = cmd " -e '\''s/(^|[^a-zA-Z0-9_-])-([a-zA-Z0-9]|-[a-zA-Z0-9_-]{1,})/\\1B<-\\2>/g'\''"
184 cmd = cmd " -e '\''s/(^|[^a-zA-Z0-9_-])\\*([a-zA-Z0-9_-]{1,})\\*([^a-zA-Z0-9_-]|$)/\\1B<\\2>\\3/g'\''"
185 cmd | getline l; close(cmd)
190 /^\t/ && section == "use" {
192 if ($1 ~ /^[-a-zA-Z0-9_+.=]+$/) print "B<" $1 ">"
194 $1=""; gsub(/<[-a-zA-Z_]+>/,"I&"); line($0); sep(1); next
197 !/^\t\t[ \t]/ && list { if (verbatim) sep(1); verbatim=0 }
198 /^\t\t[ \t]/ && list {
199 if (!verbatim) { verbatim=1; sep(1) }
200 sub(/^\t\t/,""); line($0); next
202 # List/Option description
204 sub(/^\t\t/, ""); line(style($0)); next
209 list=1; sline("=over 4")
211 sep(-1); print "=item "
212 sub(/^ *\t/, ""); line(item($0)); sep(1); next
215 !/^\t[ \t]/ { if (verbatim) sep(1); verbatim=0 }
217 if (!verbatim) { verbatim=1; sep(1) }
218 sub(/^\t/,""); line($0); next
222 sub(/^\t/,""); line(style($0)); next
224 # Detect unrecognized skipped lines
225 { invalid++; _blank=0 }
228 if (list) { sep(-1); print "=back\n" }
230 print PROGRAM_NAME ": error: " invalid " invalid lines skipped\n" > "/dev/fd/2"
235 gsub(/'/, \"'\\\\''\", s); return \"'\" s \"'\"
240 (set -o pipefail
) 2>/dev
/null
&& set -o pipefail
241 if [ -n "$MAN" ] && [ -t 1 ]
243 process
"$@" |pod2man
-u -c "" ${FILE:+-n "$FILE"} ${SECTION:+-s "$SECTION"} |
244 nroff
-man |
${PAGER:-more}
247 process
"$@" |pod2man
-u -c "" ${FILE:+-n "$FILE"} ${SECTION:+-s "$SECTION"}