version/0.2
[shelmfish.git] / helpm4sh
blobc0ca9aa91932aa928ea118bd6bb185b3cf16c0e8
1 #!/bin/sh
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
11 # details.
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="helpm4sh"
17 PROGRAM_VERSION="0.2"
18 # <<"HelpMessage"
19 #NAME
20 # helpm4sh - extract embedded HelpMessage/POD from sh scripts
21 #SYNOPSIS
22 # helpm4sh [--] <format>[-] [<file>]
23 #HelpMessage
25 while [ $# -gt 0 ]
27 case $1 in
28 -V|--version) echo "$PROGRAM_NAME version $PROGRAM_VERSION"; exit ;;
29 --?*) echo >&2 "$PROGRAM_NAME: error: invalid option"; exit 255 ;;
30 --) shift; break ;;
31 *) break ;;
32 esac
33 done
34 if [ $# -eq 0 ]
35 then echo >&2 "$PROGRAM_NAME: error: missing format argument"; exit 255
37 FORMAT=$1; shift
38 if [ $# -gt 1 ]
39 then echo >&2 "$PROGRAM_NAME: error: too many arguments"; exit 255
41 if [ $# -gt 0 ] && expr "$1" : '[a-zA-Z_][a-zA-Z_0-9]*=' >/dev/null
42 then set -- ./"$1"
45 awk -v PROGRAM_NAME="$PROGRAM_NAME" -v FORMAT="$FORMAT" '
46 BEGIN {
47 if (sub(/-$/,"", FORMAT))
48 doc = 0
49 else
50 doc = 1
51 if (tolower(FORMAT) ~ /^help(m|message)$|^hm$/) {
52 FORMAT = "HelpMessage"
53 start = "_*(HelpM|helpm|HELPM)(essage)*"
55 else if (tolower(FORMAT) ~ /^pod$/) {
56 FORMAT = "POD"
57 start = "=cut"
59 else {
60 print PROGRAM_NAME ": error: unknown format", FORMAT > "/dev/fd/2"
61 start = ""; exit
63 block = 0; dynamic = 0
65 # start of block
66 $0 ~ "<< *\"" start "\"$" && block <= 0 {
67 block = 1 - block
68 end = $0; sub(/^.*<< *"/,"^",end); sub(/"$/,"",end)
69 if (/^[ \t]*#/) com = 1; else com = 0
70 if (com) sub(/^\^/,"^[ \t]*#",end)
71 if (doc)
72 next
73 else {
74 sub("<< *\"" start "\"$","</dev/null")
75 print
78 # end of block
79 $0 ~ end && block > 0 {
80 block = -block
81 next
83 # inside a block
84 block > 0 && doc {
85 if (com) sub(/^[ \t]*#/,"")
86 print
88 # outside of any block
89 block <= 0 {
90 if ($0 ~ "<< *" start " *$") dynamic++
91 if (!doc) print
93 END {
94 print PROGRAM_NAME ":", (block < 0 ? -block : block), \
95 "blocks of " FORMAT " extracted" > "/dev/fd/2"
96 if (dynamic) {
97 print PROGRAM_NAME ": warning:", dynamic " dynamic blocks detected"
98 exit 2
100 if (block == 0) exit 1
101 }' "${1--}"
103 # <<"HelpMessage"
104 #DESCRIPTION
105 # helpm4sh extracts constant help messages from the given <file>, or from
106 # standard input if <file> is a dash or is not given. If <format> is
107 # *helpm*, embedded HelpMessage blocks are extracted. The blocks can be
108 # either here documents starting by a line matching the regular expression
109 # C< << *"_*(HELPM|HelpM|helpm)(essage)?"$>, or be similar here documents in
110 # comments.
112 # If <format> is *pod*, then here documents (or here documents in comments)
113 # delimited by "=cut" are extracted.
115 # If a dash is appended to <format>, then the here documents are stripped.
116 #EXIT STATUS
117 # If no blocks are found or if "dynamic" blocks (whose delimiter is unquoted)
118 # are detected, the return status is non zero.
119 #EXAMPLES
120 # This manual page can be extracted from the script itself:
121 # $ helpm4sh helpm $(where helpm4sh) | helpm2man - HELPM4SH.1
122 #AUTHOR
123 # helpm4sh was written by G.raud Meyer.
124 #SEE ALSO
125 # helpmessage(5), perlpod(1)
126 #HelpMessage