#!/bin/bash # Copyright 2004-2021 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # written by Aron Griffis EPREFIX='' ROOTCONFDIR="${EPREFIX}"/etc/xml ROOTCATALOG=${ROOTCONFDIR}/catalog CATALOG=${ROOTCONFDIR}/docbook DOCBOOKDIR="${EPREFIX}"/usr/share/sgml/docbook LOCKDIR=${EPREFIX}/etc/xml/.lock DTDS=() SIMPLE_DTDS=() LATEST_DTD= LATEST_DATE= VERBOSE=false ZERO=${0##*/} GETOPT=getopt # # usage! # usage() { cat <<-EOF Usage: ${ZERO} [options] Regenerate the XML docbook catalog under ${ROOTCONFDIR}. Options: -r, --root Path to work on (defaults to \$ROOT) -v, --verbose Be verbose -x, --debug Run with debugging enabled -h, --help This! EOF [[ $# -gt 0 ]] && eerror "$*" exit 0 } # # main (called from bottom) # main() { local d v opts opts=$(${GETOPT} -o hr:vx --long help,root:,verbose,debug -n "${ZERO}" -- "$@") || exit 1 eval set -- "${opts}" while true; do case $1 in -h|--help) usage ;; -r|--root) ROOT=$2 ; shift ;; -v|--verbose) VERBOSE=true ;; -x|--debug) set -x ;; --) break ;; *) usage "options parsing failed on $1!" ;; esac shift done : "${ROOT:=/}" [[ ${ROOT} != */ ]] && ROOT="${ROOT}/" [[ ${ROOT} != /* ]] && ROOT="${PWD}${ROOT}" if [[ ${ROOT} != "/" ]] ; then echo "Working on root ${ROOT}" fi [[ // -ef / ]] || ROOT="/.${ROOT}" # "//" might refer to network if [[ ! -d ${ROOT}${ROOTCONFDIR} ]] ; then mkdir -p "${ROOT}${ROOTCONFDIR}" || error "could not create ${ROOTCONFDIR}" fi local lock_dir="${ROOT}${LOCKDIR}" if [[ ! -d ${lock_dir} ]] ; then mkdir -p "${lock_dir}" fi local lock="${lock_dir}/build-docbook-catalog.lock" ( # Lock the dir to avoid trashing other runs that might # be running parallel. flock 200 create_catalogs # will exit on error for type in xsl xsl-ns xsl-saxon xsl-xalan; do populate_xsl ${type} done # Clean out old dtds from catalog verb "Cleaning out old DocBook XML versions from ${CATALOG} and ${ROOTCATALOG}" clean_catalog "${DOCBOOKDIR}/xml\(-simple\)*-dtd-[^/\"']*/[^/\"']*" "${CATALOG}.tmp" clean_catalog "${DOCBOOKDIR}/xml\(-simple\)*-dtd-[^/\"']*/[^/\"']*" "${ROOTCATALOG}.tmp" if set_dtds; then for d in "${DTDS[@]}"; do populate_dtd "${d}" done for d in "${SIMPLE_DTDS[@]}"; do populate_simple_dtd "${d}" done populate_entities fi sed -i \ -e "s:${ROOTCATALOG}\.tmp:${ROOTCATALOG}:g" \ -e "s:${CATALOG}\.tmp:${CATALOG}:g" \ "${ROOT}${ROOTCATALOG}.tmp" \ "${ROOT}${CATALOG}.tmp" || error "could not clean up" mv "${ROOT}${ROOTCATALOG}.tmp" "${ROOT}${ROOTCATALOG}" mv "${ROOT}${CATALOG}.tmp" "${ROOT}${CATALOG}" # NB: Don't delete the lock since we can't delete files by fd, and if we do # it by path, we might delete the lock while other processes grab it. ) 200>>"${lock}" exit 0 } # # verbose echo -- only echo if called with --verbose # verb() { ${VERBOSE} && echo "$*" } # # show an error and abort # error() { printf '%s: %b, aborting\n' "${ZERO}" "$*" 1>&2 exit 1 } # # fill in the DTDS variable based on installed versions # set_dtds() { DTDS=() SIMPLE_DTDS=() local d=${ROOT}${DOCBOOKDIR} if [[ -d ${d} ]] ; then pushd "${d}" >/dev/null || return 1 shopt -s nullglob DTDS=( xml-dtd-*/docbookx.dtd ) SIMPLE_DTDS=( xml-simple-dtd-*/sdocbook.dtd ) shopt -u nullglob popd >/dev/null || return 1 fi if [[ ${#DTDS[@]} -eq 0 ]]; then echo "No installed DocBook XML DTDs found" return 1 else return 0 fi } # # multi_xmlcatalog_add # # the opts array is a set of three: what gets passed to --add # multi_xmlcatalog_add() { local file="${ROOT}$1" shift while [[ $# -gt 0 ]] ; do xmlcatalog --noout --add "$1" "$2" "file://$3" "${file}" shift 3 done } # # create the catalogs root and docbook specific # create_catalogs() { local adds # Initialize catalogs if they don't exist or are corrupt. if [[ -r ${ROOT}${ROOTCATALOG} ]] && ! xmllint "${ROOT}${ROOTCATALOG}" >&/dev/null ; then rm -f "${ROOT}${ROOTCATALOG}" echo "Deleting corrupt ${ROOT}${ROOTCATALOG} and starting over" fi if [[ ! -r ${ROOT}${ROOTCATALOG} ]] ; then echo "Creating XML Catalog root ${ROOTCATALOG}" xmlcatalog --noout --create "${ROOT}${ROOTCATALOG}" if [[ ! -r ${ROOT}${ROOTCATALOG} ]] ; then error "failed creating ${ROOTCATALOG}" fi cp "${ROOT}${ROOTCATALOG}" "${ROOT}${ROOTCATALOG}.tmp" else verb "Found XML Catalog root ${ROOTCATALOG}" # clean out existing entries verb " Cleaning existing ${CATALOG} delegates from ${ROOTCATALOG}" cp "${ROOT}${ROOTCATALOG}" "${ROOT}${ROOTCATALOG}.tmp" clean_catalog "file://${CATALOG}" "${ROOTCATALOG}.tmp" fi # Initialize catalogs if they don't exist or are corrupt. if [[ -r ${ROOT}${CATALOG} ]] && ! xmllint "${ROOT}${CATALOG}" >&/dev/null ; then rm -f "${ROOT}${CATALOG}" echo "Deleting corrupt ${CATALOG} and starting over" fi if [[ ! -r ${ROOT}${CATALOG} ]] ; then echo "Creating DocBook XML Catalog ${CATALOG}" xmlcatalog --noout --create "${ROOT}${CATALOG}" if [[ ! -r ${ROOT}${CATALOG} ]] ; then error "failed creating ${CATALOG}" fi else verb "Found DocBook XML Catalog ${CATALOG}" fi cp "${ROOT}${CATALOG}" "${ROOT}${CATALOG}.tmp" # dtd pointers verb " Populating ${ROOTCATALOG} with DTD delegates to ${CATALOG}" adds=( "delegatePublic" "-//OASIS//ENTITIES DocBook" "${CATALOG}.tmp" "delegatePublic" "-//OASIS//ELEMENTS DocBook" "${CATALOG}.tmp" "delegatePublic" "-//OASIS//DTD DocBook" "${CATALOG}.tmp" "delegateSystem" "http://www.oasis-open.org/docbook/" "${CATALOG}.tmp" "delegateURI" "http://www.oasis-open.org/docbook/" "${CATALOG}.tmp" ) multi_xmlcatalog_add "${ROOTCATALOG}.tmp" "${adds[@]}" # entities pointer verb " Populating ${ROOTCATALOG} with ISO entities delegate to ${CATALOG}" adds=( "delegatePublic" "ISO 8879:1986" "${CATALOG}.tmp" ) multi_xmlcatalog_add "${ROOTCATALOG}.tmp" "${adds[@]}" } # # clean_catalog # $1 == regex to clean # $2 == catalog # clean_catalog() { local list f regex=$1 catalog=${ROOT}$2 list=$(grep -E --only-matching "${regex}" "${catalog}" | sort -u) for f in ${list}; do xmlcatalog --noout --del "${f}" "${catalog}" done } # # populate a specific dtd version into the docbook catalog # $1 == ./subpath/to/docbookx.dtd # populate_dtd() { local dtd=${DOCBOOKDIR}/$1 local docbookdir=${dtd%/*} local v=${docbookdir##*-} local adds dtd_date # sanity check if [[ ${dtd} != */xml-dtd-*/* ]]; then echo "Warning: I don't understand \"${dtd}\"" >&2 return fi echo "Found DocBook XML ${v} in ${docbookdir}" # Populate the docbook catalog with this version verb " Populating ${CATALOG} based on ${docbookdir}" adds=( "public" "-//OASIS//ELEMENTS DocBook XML Information Pool V${v}//EN" "${docbookdir}/dbpoolx.mod" "public" "-//OASIS//DTD DocBook XML V${v}//EN" "${docbookdir}/docbookx.dtd" "public" "-//OASIS//ENTITIES DocBook XML Character Entities V${v}//EN" "${docbookdir}/dbcentx.mod" "public" "-//OASIS//ENTITIES DocBook XML Notations V${v}//EN" "${docbookdir}/dbnotnx.mod" "public" "-//OASIS//ENTITIES DocBook XML Additional General Entities V${v}//EN" "${docbookdir}/dbgenent.mod" "public" "-//OASIS//ELEMENTS DocBook XML Document Hierarchy V${v}//EN" "${docbookdir}/dbhierx.mod" "public" "-//OASIS//DTD XML Exchange Table Model 19990315//EN" "${docbookdir}/soextblx.dtd" "public" "-//OASIS//DTD DocBook XML CALS Table Model V${v}//EN" "${docbookdir}/calstblx.dtd" "rewriteSystem" "http://www.oasis-open.org/docbook/xml/${v}" "${docbookdir}" "rewriteURI" "http://www.oasis-open.org/docbook/xml/${v}" "${docbookdir}" ) multi_xmlcatalog_add "${CATALOG}.tmp" "${adds[@]}" # grab the RCS date from docbookx.dtd for comparison purposes if [[ ! -f ${ROOT}${docbookdir}/ent/iso-lat1.ent ]]; then verb " No entities available for ${dtd}" return 0 fi dtd_date=$(grep -E --only-matching --max-count=1 \ '[0-9]{4}/[0-9]{2}/[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}' \ "${ROOT}${dtd}") if [[ -z ${dtd_date} ]]; then verb " Couldn't find RCS date in ${dtd}, ignoring entities" return 0 fi verb " RCS datestamp in ${dtd} is ${dtd_date}" dtd_date=$(date -d "${dtd_date}" +%s) if [[ ${dtd_date} -gt ${LATEST_DATE:-0} ]] ; then LATEST_DATE=${dtd_date} LATEST_DTD=${dtd} fi } # # populate a specific simple dtd version into the docbook catalog # $1 == ./subpath/to/sdocbook.dtd # populate_simple_dtd() { local dtd=${DOCBOOKDIR}/$1 local docbookdir=${dtd%/*} local v=${docbookdir##*-} local adds dtd_date # sanity check if [[ ${dtd} != */xml-simple-dtd-*/* ]]; then echo "Warning: I don't understand \"${dtd}\"" >&2 return fi echo "Found Simplified DocBook XML ${v} in ${docbookdir}" # Populate the docbook catalog with this version verb " Populating ${CATALOG} based on ${docbookdir}" adds=( "public" "-//OASIS//DTD Simplified DocBook XML V${v}//EN" "${docbookdir}/sdocbook.dtd" "rewriteSystem" "http://www.oasis-open.org/docbook/xml/simple/${v}" "${docbookdir}" "rewriteURI" "http://www.oasis-open.org/docbook/xml/simple/${v}" "${docbookdir}" ) multi_xmlcatalog_add "${CATALOG}.tmp" "${adds[@]}" } # # populate ISO DocBook entities from the most recent DTD # populate_entities() { local isodir=${LATEST_DTD%/*}/ent i j local entities=() avail=() # sanity check if [[ -z ${LATEST_DTD} || ! -d ${ROOT}${isodir} ]]; then echo "No ISO DocBook entities available for catalog" return 0 fi echo "Using ISO DocBook entities from ${isodir}" # here are the entities we know about; # note these must remain sorted! entities=( "iso-amsa.ent" "ISO 8879:1986//ENTITIES Added Math Symbols: Arrow Relations//EN" "iso-amsb.ent" "ISO 8879:1986//ENTITIES Added Math Symbols: Binary Operators//EN" "iso-amsc.ent" "ISO 8879:1986//ENTITIES Added Math Symbols: Delimiters//EN" "iso-amsn.ent" "ISO 8879:1986//ENTITIES Added Math Symbols: Negated Relations//EN" "iso-amso.ent" "ISO 8879:1986//ENTITIES Added Math Symbols: Ordinary//EN" "iso-amsr.ent" "ISO 8879:1986//ENTITIES Added Math Symbols: Relations//EN" "iso-box.ent" "ISO 8879:1986//ENTITIES Box and Line Drawing//EN" "iso-cyr1.ent" "ISO 8879:1986//ENTITIES Russian Cyrillic//EN" "iso-cyr2.ent" "ISO 8879:1986//ENTITIES Non-Russian Cyrillic//EN" "iso-dia.ent" "ISO 8879:1986//ENTITIES Diacritical Marks//EN" "iso-grk1.ent" "ISO 8879:1986//ENTITIES Greek Letters//EN" "iso-grk2.ent" "ISO 8879:1986//ENTITIES Monotoniko Greek//EN" "iso-grk3.ent" "ISO 8879:1986//ENTITIES Greek Symbols//EN" "iso-grk4.ent" "ISO 8879:1986//ENTITIES Alternative Greek Symbols//EN" "iso-lat1.ent" "ISO 8879:1986//ENTITIES Added Latin 1//EN" "iso-lat2.ent" "ISO 8879:1986//ENTITIES Added Latin 2//EN" "iso-num.ent" "ISO 8879:1986//ENTITIES Numeric and Special Graphic//EN" "iso-pub.ent" "ISO 8879:1986//ENTITIES Publishing//EN" "iso-tech.ent" "ISO 8879:1986//ENTITIES General Technical//EN" ) # here are the entities available; assume no spaces in filenames... mapfile -d $'\0' avail < <(find "${ROOT}${isodir}" -maxdepth 1 -type f -printf '%f\0' | sort -z) # double-check the lists verb " Populating ${CATALOG} with ${#avail[@]} ISO DocBook entities" i=0 ; j=0 while [[ ${i} -lt ${#entities[@]} || ${j} -lt ${#avail[@]} ]]; do if [[ ${i} -ge ${#entities[@]} ]]; then echo "Warning: Extra ISO entities file: ${avail[j]}" : $(( j += 1 )) elif [[ ${j} -ge ${#avail[@]} ]]; then echo "Warning: Entities file not found: ${entities[i]}" : $(( i += 2 )) elif [[ ${avail[j]} < "${entities[i]}" ]]; then echo "Warning: Extra ISO entities file: ${avail[j]}" : $(( j += 1 )) elif [[ ${entities[i]} < "${avail[j]}" ]]; then echo "Warning: Entities file not found: ${entities[i]}" : $(( i += 2 )) elif [[ ${entities[i]} == "${avail[j]}" ]]; then xmlcatalog --noout --add "public" "${entities[i+1]}" \ "file://${isodir}/${entities[i]}" "${ROOT}${CATALOG}.tmp" : $(( j += 1 )) : $(( i += 2 )) else error "${0}: whoah, shouldn't be here" fi done } # # populate XSL stylesheets # populate_xsl() { local f adds # This is either xsl, xsl-ns, xsl-saxon or xsl-xalan local type=$1 # Delete current entries from the catalog (delete legacy versioned entries too) clean_catalog "${DOCBOOKDIR}/${type}-stylesheets(-[0-9\.]+)?" "${CATALOG}.tmp" clean_catalog "${DOCBOOKDIR}/${type}-stylesheets(-[0-9\.]+)?" "${ROOTCATALOG}.tmp" local xsldir=${DOCBOOKDIR}/${type}-stylesheets if [[ ! -d ${ROOT}${xsldir} ]] ; then echo "DocBook XSL stylesheets (${type}) not found" >&2 return 1 fi if [[ ! -e ${ROOT}${xsldir}/html/docbook.xsl || ! -e ${ROOT}${xsldir}/common/l10n.xml ]] ; then echo "DocBook XSL stylesheets are missing files from ${xsldir}" >&2 return 1 fi # Populate catalog with XSL entries echo "Found DocBook XSL stylesheets (${type}) in ${xsldir}" verb " Populating ${ROOTCATALOG} with XSL delegations" adds=( "delegateSystem" "http://docbook.sourceforge.net/release/${type}/" "${CATALOG}.tmp" "delegateURI" "http://docbook.sourceforge.net/release/${type}/" "${CATALOG}.tmp" ) multi_xmlcatalog_add "${ROOTCATALOG}.tmp" "${adds[@]}" verb " Populating ${CATALOG} with XSL stylesheets" adds=( "rewriteSystem" "http://docbook.sourceforge.net/release/${type}/current" "${xsldir}" "rewriteURI" "http://docbook.sourceforge.net/release/${type}/current" "${xsldir}" ) multi_xmlcatalog_add "${CATALOG}.tmp" "${adds[@]}" } # Call the main routine main "$@"