]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/kyua/doc/manbuild.sh
Import the kyua test framework.
[FreeBSD/FreeBSD.git] / contrib / kyua / doc / manbuild.sh
1 #! /bin/sh
2 # Copyright 2014 The Kyua Authors.
3 # All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
7 # met:
8 #
9 # * Redistributions of source code must retain the above copyright
10 #   notice, this list of conditions and the following disclaimer.
11 # * Redistributions in binary form must reproduce the above copyright
12 #   notice, this list of conditions and the following disclaimer in the
13 #   documentation and/or other materials provided with the distribution.
14 # * Neither the name of Google Inc. nor the names of its contributors
15 #   may be used to endorse or promote products derived from this software
16 #   without specific prior written permission.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 # \file doc/manbuild.sh
31 # Generates a manual page from a source file.
32 #
33 # Input files can have __VAR__-style patterns in them that are replaced
34 # with the values provided by the caller via the -v VAR=VALUE flag.
35 #
36 # Input files can also include other files using the __include__ directive,
37 # which takes a relative path to the file to include plus an optional
38 # collection of additional variables to replace in the included file.
39
40
41 # Name of the running program for error reporting purposes.
42 Prog_Name="${0##*/}"
43
44
45 # Prints an error message and exits.
46 #
47 # Args:
48 #   ...: The error message to print.  Multiple arguments are joined with a
49 #       single space separator.
50 err() {
51     echo "${Prog_Name}: ${*}" 1>&2
52     exit 1
53 }
54
55
56 # Invokes sed(1) translating input variables to expressions.
57 #
58 # Args:
59 #   ...: List of var=value pairs to replace.
60 #
61 # Returns:
62 #   True if the operation succeeds; false otherwise.
63 sed_with_vars() {
64     local vars="${*}"
65
66     set --
67     for pair in ${vars}; do
68         local var="$(echo "${pair}" | cut -d = -f 1)"
69         local value="$(echo "${pair}" | cut -d = -f 2-)"
70         set -- "${@}" -e"s&__${var}__&${value}&g"
71     done
72
73     if [ "${#}" -gt 0 ]; then
74         sed "${@}"
75     else
76         cat
77     fi
78 }
79
80
81 # Generates the manual page reading from stdin and dumping to stdout.
82 #
83 # Args:
84 #   include_dir: Path to the directory containing the include files.
85 #   ...: List of var=value pairs to replace in the manpage.
86 #
87 # Returns:
88 #   True if the generation succeeds; false otherwise.
89 generate() {
90     local include_dir="${1}"; shift
91
92     while :; do
93         local read_ok=yes
94         local oldifs="${IFS}"
95         IFS=
96         read -r line || read_ok=no
97         IFS="${oldifs}"
98         [ "${read_ok}" = yes ] || break
99
100         case "${line}" in
101             __include__*)
102                 local file="$(echo "${line}" | cut -d ' ' -f 2)"
103                 local extra_vars="$(echo "${line}" | cut -d ' ' -f 3-)"
104                 # If we fail to output the included file, just leave the line as
105                 # is.  validate_file() will later error out.
106                 [ -f "${include_dir}/${file}" ] || echo "${line}"
107                 generate <"${include_dir}/${file}" "${include_dir}" \
108                     "${@}" ${extra_vars} || echo "${line}"
109                 ;;
110
111             *)
112                 echo "${line}"
113                 ;;
114         esac
115     done | sed_with_vars "${@}"
116 }
117
118
119 # Validates that the manual page has been properly generated.
120 #
121 # In particular, this checks if any directives or common replacement patterns
122 # have been left in place.
123 #
124 # Returns:
125 #   True if the manual page is valid; false otherwise.
126 validate_file() {
127     local filename="${1}"
128
129     if grep '__[A-Za-z0-9]*__' "${filename}" >/dev/null; then
130         return 1
131     else
132         return 0
133     fi
134 }
135
136
137 # Program entry point.
138 main() {
139     local vars=
140
141     while getopts :v: arg; do
142         case "${arg}" in
143             v)
144                 vars="${vars} ${OPTARG}"
145                 ;;
146
147             \?)
148                 err "Unknown option -${OPTARG}"
149                 ;;
150         esac
151     done
152     shift $((${OPTIND} - 1))
153
154     [ ${#} -eq 2 ] || err "Must provide input and output names as arguments"
155     local input="${1}"; shift
156     local output="${1}"; shift
157
158     trap "rm -f '${output}.tmp'" EXIT HUP INT TERM
159     generate "$(dirname "${input}")" ${vars} \
160         <"${input}" >"${output}.tmp" \
161         || err "Failed to generate ${output}"
162     if validate_file "${output}.tmp"; then
163         :
164     else
165         err "Failed to generate ${output}; some patterns were left unreplaced"
166     fi
167     mv "${output}.tmp" "${output}"
168 }
169
170
171 main "${@}"