#!/bin/sh
#
# mkcatalog - script for making sgml catalog file.
#
# Created:  20001015  Shigeyuki Fukushima <shige@FreeBSD.org>.
# Modified: 20001019  Hiroki Sato <hrs@FreeBSD.org>.
#
# $FreeBSD: head/textproc/mkcatalog/files/mkcatalog.in 404857 2015-12-30 14:07:42Z ak $
#
sh_basename ()
{
    l_value=$1
    IFS_old=${IFS}; IFS=" /"; set -- ${l_value}; IFS=${IFS_old}
    case $# in
    0) ;;
    *) echo `eval echo \\$$#` ;;
    esac
}

sh_dirname ()
{
    l_value=$1
    IFS_old=${IFS}; IFS=" /"; set -- ${l_value}; IFS=${IFS_old}
    l_dirname=$1; shift;
    while
        case $# in
        0) break ;;
        1) echo ${l_dirname}; break ;;
        *) ;;
        esac;
    do
        l_dirname="${l_dirname}/$1";
        shift;
    done
}

norm_dir ()
{
    [ -d "$1" ] && echo `exec 2>/dev/null; cd $1; echo ${PWD}`
}

verbose_msg ()
{
    case ${F_VERBOSE} in
    1) echo " ===> $*" ;;
    *) ;;
    esac
}

PREFIX=%%PREFIX%%
TMPDIR=/tmp
ARGV0=`sh_basename $0`

# default top-level catalog file
CAT_DIR=${PREFIX}/share/sgml
CAT_FILE=catalog

F_PRESERVE_OLD=""
F_VERBOSE=""
args=`getopt pqvc: $*` ; set -- $args
for i
do
    case "$i" in
    -c) CAT_DIR=`sh_dirname $2`;
        CAT_FILE=`sh_basename $2`;
        shift; shift ;;
    -p) F_PRESERVE_OLD=1;        shift ;;
    -q) exec 1> /dev/null 2>&1;  shift ;;
    -v) F_VERBOSE=1;             shift ;;
    --)                          shift; break ;;
    esac
done

dtd_act=$1
dtd_dir=$2
dtd_catalog=`sh_basename "$3"`

### option check and normalize ${dtd_dir}
case "${dtd_act}" in
add|install|delete|deinstall|enable|disable)
    if [ ! -d "${CAT_DIR}" ]; then
        echo "${ARGV0}: top-level catalog dir \"${CAT_DIR}\" not found."
        exit 1
    elif [ ! -n "${dtd_dir}" ]; then
        echo "${ARGV0}: DTD directory is not specified."
        exit 1
    elif [    ! -d "${CAT_DIR}/${dtd_dir}"\
           -a ! -d "${dtd_dir}" ]; then
        echo "${ARGV0}: DTD directory \"${dtd_dir}\" not found."
        exit 1
    elif [    ! -f "${CAT_DIR}/${dtd_dir}/${dtd_catalog:-catalog}"\
           -a ! -f "${dtd_dir}/${dtd_catalog:-catalog}" ]; then
        echo "${ARGV0}: DTD catalog \"${dtd_dir}/${dtd_catalog:-catalog}\" not found."
        exit 1
    fi
    verbose_msg "top-level catalog dir (specified):  ${CAT_DIR}"
    CAT_DIR=`norm_dir ${CAT_DIR}`
    verbose_msg "top-level catalog dir (normalized): ${CAT_DIR}"
    verbose_msg "target catalog dir (specified): ${dtd_dir}"
    dtd_dir=`norm_dir ${CAT_DIR}/${dtd_dir} || norm_dir ${dtd_dir}`
    verbose_msg "target catalog dir (normalized): ${dtd_dir}"

    case "${dtd_dir}" in
    ${CAT_DIR}/*) ;;
    *)  echo "${ARGV0}: DTD directory \"${dtd_dir}\" is invalid."
        exit 1 ;;
    esac
    ### keep dtd_dir relative
    dtd_dir=${dtd_dir#"${CAT_DIR}/"}
    ;;
*)
    echo "${ARGV0}: missing options."
    cat <<EOF

Usage:
 ${ARGV0} [-c toplv-catalog-filename] [-pqv] [install|add|deinstall|delete|enable|disable] dtd-directory-name [catalog-filename].

        -c filename   specifies top-level catalog file
                      (default: ${CAT_DIR}/${CAT_FILE})
        -p            preseve old catalog file (as .old)
        -q            quiet mode
        -v            verbose mode (for debug)

 ex.) mkcatalog install html/4.0
      mkcatalog -c /home/foo/sgml/catalog install html/4.0/my_ext html_catalog
EOF
    exit 1 ;;
esac

echo "* top-level catalog: ${CAT_DIR}/${CAT_FILE}"
verbose_msg "action:              ${dtd_act}"
verbose_msg "target catalog dir:  ${dtd_dir}"
verbose_msg "target catalog file: ${dtd_catalog:-catalog}"

echo "* attempt to ${dtd_act} catalog in ${dtd_dir}"
TMPCAT=/tmp/catalog.$$

proc_catalog ()
{
    l_bottom_p=$1 # allow to delete upper catalog?
    l_upper=$2    # dirname of upper catalog
    l_lower=$3    # dirname of lower catalog

    case ${first_p} in
    [Yy][Ee][Ss]) catalog=${dtd_catalog:-"catalog"} ;;
    *)            catalog=${CAT_FILE} ;;
    esac

    # l_upper_cat -> relative path from ${CAT_DIR}
    # l_lower_cat -> relative path from l_upper
    l_upper_cat=${l_upper}/${CAT_FILE}
    l_lower_cat=`sh_basename ${l_lower}`/${catalog}

    # l_*_abs_* -> absolute path respectively
    l_upper_abs=${CAT_DIR}/${l_upper}
    l_lower_abs=${CAT_DIR}/${l_lower}
    l_upper_abs_cat=${CAT_DIR}/${l_upper}/${CAT_FILE}
    l_lower_abs_cat=${CAT_DIR}/${l_lower}/${catalog}

    # for debug
    #echo ${l_bottom_p} ${l_upper_cat} ${l_lower_cat}

    l_cat_line="CATALOG \"${l_lower_cat}\""
    l_abs_path_head=`cd ${l_upper_abs}; echo ${PWD}`

    # for debug
    #echo ${l_cat_line}

    # first, create temporary catalog from l_upper_cat
    # not including CATALOG line of l_lower_cat (if no catalog,
    # create empty one).
    #
    # NOTE: file manipulations require absolute path, but
    #       CATALOG line do relative from upper's one.
    #
    touch ${l_upper_abs_cat} || exit 1
    grep -v "\( *-- *\)\?CATALOG *\"\(${l_abs_path_head}/\)\?${l_lower_cat}\"\( *-- *\)\?" ${l_upper_abs_cat} > ${TMPCAT}

    # preserve old catalog as necessary
    if [ "x${F_PRESERVE_OLD}" != "x" ]; then
        cp ${l_upper_abs_cat} ${l_upper_abs_cat}.old || exit 1
    fi

    case "${dtd_act}" in
    add|install|enable)
        #
        # if "install or add or enable",
        # create "the tamporary catalog + l_cat_line" and install it.
        #
        echo " - ${dtd_act} ${l_cat_line} line in ${l_upper_cat}"
        echo "${l_cat_line}" >> ${TMPCAT}
        cp ${TMPCAT} ${l_upper_abs_cat} || exit 1
        ;;
    disable)
        #
        # if "disable", install the same above but l_cat_line is
        # commented out.
        #
        case ${first_p} in
        [Yy][Ee][Ss])
            echo " - ${dtd_act} ${l_cat_line} line in ${l_upper_cat}"
            echo "-- ${l_cat_line} --" >> ${TMPCAT}
            cp ${TMPCAT} ${l_upper_abs_cat} || exit 1
            ;;
        *)  rm -f ${TMPCAT};
            exit 0;
            ;;
        esac
        ;;
    delete|deinstall)
        #
        # if "deinstall or delete" and the temporary catalog is
        # not empty, install the catalog itself (in the case of being
        # empty, delete it).  ${l_bottom_p}=YES means that
        # ${l_upper_cat} can be deleted safely, otherwise not.
        #
        case ${l_bottom_p} in
        [Yy][Ee][Ss])
            echo " - ${dtd_act} ${l_cat_line} line from ${l_upper_cat}"
            if [ ! -s ${TMPCAT} ]; then
                echo " - delete empty catalog ${l_upper_cat}"
                rm -f ${l_upper_abs_cat}
            else
                cp ${TMPCAT} ${l_upper_abs_cat} || exit 1
            fi
            ;;
        *)  rm -f ${TMPCAT};
            exit 0;
            ;;
        esac
        ;;
    esac

    #
    # when flag "preserve old" is specified but
    # there is no difference between new file and old one,
    # preservation is silently denied.
    #
    if [ "x${F_PRESERVE_OLD}" != "x" ] && \
       cmp -s ${l_upper_abs_cat}.old ${l_upper_abs_cat}; then
        rm -f ${l_upper_abs_cat}.old
    fi
    rm -f ${TMPCAT}
}

compose_dir_list ()
{
    l_dir=$1
    #
    # Creates dirlist such as the following.
    #  input:  docbook/4.1/my_extension
    #  return: docbook/4.1/my_extension docbook/4.1 docbook
    #
    IFS_old=${IFS}; IFS=" /"; set -- ${l_dir}
    l_dir_top=$1;
    shift;
    l_dir_rest=$*;
    IFS=${IFS_old}

    l_dir_item=${l_dir_top}
    l_dir_list=${l_dir_top}

    for i in ${l_dir_rest}
    do
        l_dir_item="${l_dir_item}/${i}"
        l_dir_list="${l_dir_item} ${l_dir_list}"
    done
    echo ${l_dir_list}
}

bottom_p=YES
first_p=YES

set -- `compose_dir_list ${dtd_dir}` .
verbose_msg "process catalog (relative to top one): $*"
while
    case $# in
    1) break ;;
    *) ;;
    esac;
do
    lower=$1
    upper=$2
    proc_catalog "${bottom_p}" "${upper}" "${lower}"

    first_p=NO
    if [ -f ${CAT_DIR}/${upper}/${CAT_FILE} ]; then
        bottom_p=NO
    fi
    shift;
done

exit 0;