#! /bin/sh1# Copyright 2014 The Kyua Authors.2# All rights reserved.3#4# Redistribution and use in source and binary forms, with or without5# modification, are permitted provided that the following conditions are6# met:7#8# * Redistributions of source code must retain the above copyright9# notice, this list of conditions and the following disclaimer.10# * Redistributions in binary form must reproduce the above copyright11# notice, this list of conditions and the following disclaimer in the12# documentation and/or other materials provided with the distribution.13# * Neither the name of Google Inc. nor the names of its contributors14# may be used to endorse or promote products derived from this software15# without specific prior written permission.16#17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.2829# \file doc/manbuild.sh30# Generates a manual page from a source file.31#32# Input files can have __VAR__-style patterns in them that are replaced33# with the values provided by the caller via the -v VAR=VALUE flag.34#35# Input files can also include other files using the __include__ directive,36# which takes a relative path to the file to include plus an optional37# collection of additional variables to replace in the included file.383940# Name of the running program for error reporting purposes.41Prog_Name="${0##*/}"424344# Prints an error message and exits.45#46# Args:47# ...: The error message to print. Multiple arguments are joined with a48# single space separator.49err() {50echo "${Prog_Name}: ${*}" 1>&251exit 152}535455# Invokes sed(1) translating input variables to expressions.56#57# Args:58# ...: List of var=value pairs to replace.59#60# Returns:61# True if the operation succeeds; false otherwise.62sed_with_vars() {63local vars="${*}"6465set --66for pair in ${vars}; do67local var="$(echo "${pair}" | cut -d = -f 1)"68local value="$(echo "${pair}" | cut -d = -f 2-)"69set -- "${@}" -e"s&__${var}__&${value}&g"70done7172if [ "${#}" -gt 0 ]; then73sed "${@}"74else75cat76fi77}787980# Generates the manual page reading from stdin and dumping to stdout.81#82# Args:83# include_dir: Path to the directory containing the include files.84# ...: List of var=value pairs to replace in the manpage.85#86# Returns:87# True if the generation succeeds; false otherwise.88generate() {89local include_dir="${1}"; shift9091while :; do92local read_ok=yes93local oldifs="${IFS}"94IFS=95read -r line || read_ok=no96IFS="${oldifs}"97[ "${read_ok}" = yes ] || break9899case "${line}" in100__include__*)101local file="$(echo "${line}" | cut -d ' ' -f 2)"102local extra_vars="$(echo "${line}" | cut -d ' ' -f 3-)"103# If we fail to output the included file, just leave the line as104# is. validate_file() will later error out.105[ -f "${include_dir}/${file}" ] || echo "${line}"106generate <"${include_dir}/${file}" "${include_dir}" \107"${@}" ${extra_vars} || echo "${line}"108;;109110*)111echo "${line}"112;;113esac114done | sed_with_vars "${@}"115}116117118# Validates that the manual page has been properly generated.119#120# In particular, this checks if any directives or common replacement patterns121# have been left in place.122#123# Returns:124# True if the manual page is valid; false otherwise.125validate_file() {126local filename="${1}"127128if grep '__[A-Za-z0-9]*__' "${filename}" >/dev/null; then129return 1130else131return 0132fi133}134135136# Program entry point.137main() {138local vars=139140while getopts :v: arg; do141case "${arg}" in142v)143vars="${vars} ${OPTARG}"144;;145146\?)147err "Unknown option -${OPTARG}"148;;149esac150done151shift $((${OPTIND} - 1))152153[ ${#} -eq 2 ] || err "Must provide input and output names as arguments"154local input="${1}"; shift155local output="${1}"; shift156157trap "rm -f '${output}.tmp'" EXIT HUP INT TERM158generate "$(dirname "${input}")" ${vars} \159<"${input}" >"${output}.tmp" \160|| err "Failed to generate ${output}"161if validate_file "${output}.tmp"; then162:163else164err "Failed to generate ${output}; some patterns were left unreplaced"165fi166mv "${output}.tmp" "${output}"167}168169170main "${@}"171172173