#!/bin/bash
#
# Functions for ../bin/daps
#
# Copyright (C) 2011,2012 Frank Sundermeyer <fsundermeyer@opensuse.org>
# Authors: Frank Sundermeyer <fsundermeyer@opensuse.org>
#
#


###########################################################################
#
# ARGUMENT PARSER FOR ALL SUBCOMANDS
#
# Generic parser for the subcommand's command line switches. If a function
# introduces a new switch, it needs to be added here
#
###########################################################################
function parse_args () {
    #
    # help is always handled within the function directly
    # everything else is parsed here

    # this functions only parses the getopts arguments and sets
    # variables accordingly.

    local SHORT_OPTS LONG_OPTS SUB_CMD
    SHORT_OPTS=$1
    LONG_OPTS=$2
    SUB_CMD=$3
    shift 3

    C_ARGS=$(getopt -s bash -o $SHORT_OPTS -l $LONG_OPTS -n $0 -- "$@")
    if [[ 1 = $? ]]; then
        wrong_parameter "$SUB_CMD"
    fi

    eval set -- "$C_ARGS"

    while true ; do
        case "$1" in
            --check)
                P_CHECK=1
                shift
                ;;
            --clean)
                P_CLEAN=1
                shift
                ;;
            --color)
                P_COLOR=1
                shift
                ;;
            --compact)
                P_COMPACT=1
                shift
                ;;
	    --cropmarks)
		P_CROPMARKS=1
		shift
		;;
            --css)
                if [[ $2 != "none" ]]; then
                    sanitize_path "$2" "P_CSS"
                else
                    P_CSS="$2"
                fi
                shift 2
                ;;
            --draft)
		P_DRAFT=1
		shift
		;;
            --def-file)
                sanitize_path "$2" "P_DEF_FILE"
                shift 2
                ;;
            --desktopfiles)
                P_DESKTOPFILES=1
                shift
                ;;
            --documentfiles)
                P_DOCUMENTFILES=1
                shift
                ;;
	    --epub3)
		P_EPUB3=1
		shift
		;;
            --export-dir)
                sanitize_path "$2" "P_EXPORT_DIR"
                shift 2
                ;;
            --extra-dict)
                sanitize_path "$2" "P_ASPELL_EXTRA_DICT"
                shift 2
                ;;
            --file)
                P_FILE="$2"
                shift 2
                ;;
            --formatter)
                P_FORMATTER="$2"
		shift 2
		;;
            --gen)
                P_IMAGES_GEN=1
                shift
                ;;
            --grayscale)
                P_GRAYSCALE=1
                shift
                ;;
            -h|--help)
                P_HELP=1
                shift
                ;;
            --html5)
                P_HTML5=1
                shift
                ;;
	    --jsp)
		P_JSP=1
		shift
		;;
            --lang)
                P_LANG="$2"
                shift 2
                ;;
            --list)
                P_LIST=1
                shift
                ;;
            --meta)
                P_META=1
                shift
                ;;
            --modified)
                P_MODIFIED=1
                shift
                ;;
            --name)
                P_NAME="$2"
                shift 2
                ;;
            --nodc)
                P_LIST_NODC=1
                shift
                ;;
            --noent)
                P_LIST_NOENT=1
                shift
                ;;
	    --noepub)
		P_NOEPUB=1
                shift
                ;;
            --nogzip)
                P_NOGZIP=1
                shift
                ;;
	    --nohtml)
		P_NOHTML=1
                shift
                ;;
            --noimg)
                P_LIST_NOIMG=1
                shift
                ;;
            --nopdf)
                P_NOPDF=1
                shift
                ;;
            --nosearch)
                P_NOSEARCH=1
                shift
                ;;
            --noset)
                P_NOSET=1
                shift
                ;;
            --noxml)
                P_LIST_NOXML=1
                shift
                ;;
            --online)
                P_IMAGES_ONLINE=1
                shift
                ;;
            --pagefiles)
                P_PAGEFILES=1
                shift
                ;;
            --pretty)
                P_PRETTY=1
                shift
                ;;
            --remarks)
		P_REMARKS=1
		shift
		;;
            --rootelement)
                ROOTELEMENT="$2"
		shift 2
		;;
            --rootid)
		P_ROOTID="$2"
		shift 2
		;;
            --show)
                P_SHOW=1
                shift
                ;;
            --set-date)
                P_SETDATE="$2"
                shift 2
                ;;
	    --single)
		P_HTMLSINGLE=1
		shift
		;;
            --statdir)
                sanitize_path "$2" "P_STATIC_DIR"
                shift 2
                ;;
            --static)
		P_STATIC=1
		shift
		;;
            --subdirs)
                P_SUBDIRS=1
                shift
                ;;
            --target)
                P_TARGET="$2"
		shift 2
		;;
	    --viewer)
                P_VIEWER="$2"
		shift 2
		;;
            --xsltparam)
                P_XSLTPARAM="$2"
		shift 2
		;;
            --)
                shift
                break
                ;;
            *)
                wrong_parameter "SUB_CMD"
                ;;
        esac
    done

    P_REMAIN_ARGS="$@"

}

###########################################################################
#
# INITIALIZE ENVIRONMENT
#
# Create needed directories and links
# Finally export some variables
#
###########################################################################
function init_env {
    # Create the log directory and a link to the DC-file in R_DIR
    # (R_DIR and LOG_DIR are set in bin/daps)

    local DC_COUNT TEST_ROOTID_RESULT

    # create directories

    mkdir -p $R_DIR
    if [[ 1 = $WRITE_LOG ]]; then
        mkdir -p $LOG_DIR || exit_on_error "Cannot create $LOG_DIR"
    fi


    if [[ -n $"$DOCCONF" && ! -f ${R_DIR}/$(basename "$DOCCONF") ]]; then
        ln -sf $DOCCONF ${R_DIR}/$(basename "$DOCCONF")
        if [[ 0 != $? && 0 != $VERBOSITY ]]; then
            ccecho "warn" "Warning: Cannot create link to $DOCCONF in $R_DIR"
        fi
    fi

    # There should only be one DC-file in $R_DIR
    #
    DC_COUNT=$(find -L $R_DIR -maxdepth 1 -name "${CONF_PREFIX}*" -type f | wc -l)
    if [[ $DC_COUNT -gt 1 && 0 != $VERBOSITY ]]; then
        ccecho "warn" "$R_DIR contains more than one DC-file"
    fi

    # test if ROOTID exist
    #
    if [[ -n "$ROOTID" ]]; then
        EXISTS_ROOTID=$($XSLTPROC --stringparam "rootid=$ROOTID" --xinclude --stylesheet ${DAPSROOT}/daps-xslt/common/check_rootid.xsl --file $MAIN $XSLTPROCESSOR 2>/dev/null)
        TEST_ROOTID_RESULT=$?
        if [[ 0 == $TEST_ROOTID_RESULT  && "yes" != $EXISTS_ROOTID ]]; then
            exit_on_error "Fatal: ROOTID \"$ROOTID\" does not exist."
        elif [[ 0 != $TEST_ROOTID_RESULT && 0 != $VERBOSITY ]]; then
            ccecho "warn" "Warning: Was not able to determine if ROOTID exists."
        fi
    fi

    #
    # The DocBook stylesheets require a 0|1 for REMARKS, but
    # yes|no for DRAFT
    # In order not to add to that confusion we will accept 0|1|yes|no for
    # all of them and export the correct value here. Since META falls
    # into a similar category, we also handle it the same way.
    # We also need to reset the _STR variables that get added to the resulting
    # filename here, when REMARKS, META or DRAFT has been disabled
    #
    # DRAFT must be set to yes|no
    case "$DRAFT" in
        1|yes)
            export DRAFT="yes" ;;
         0|no|"")
            export DRAFT="no" ;;
        *)
            exit_on_error "Wrong value for DRAFT. Must be \"yes\" or \"no\"" ;;
    esac

    # REMARKS must be set to 1|0
    # if enabled (set to 1) implies DRAFT mode
    case "$REMARKS" in
        1|yes)
            export REMARKS=1 DRAFT="yes" ;;
        0|no|"")
            export REMARKS=0 ;;
        *)
            exit_on_error "Invalid value for REMARKS. Must be \"yes\" or \"no\""
            ;;
        esac

    # META must be set to 1|0
    # if enabled (set to 1) implies DRAFT mode
    case "$META" in
        1|yes)
            export META=1 DRAFT="yes" ;;
          0|no|"")
            export META=0 ;;
        *)
            exit_on_error "Invalid value for META. Must be \"yes\" or \"no\""
            ;;
    esac

    # COLOR must be set to 1|0
    # if we are not in a terminal but rather in a pipe, script, etc.
    # disable color output otherwise use the value specified on the
    # command line or in the config
    if [[  -t 1 ]]; then
        case $COLOR in
            "1" | "yes")
                export COLOR=1 ;;
            "0" | "no" | "")
                COLOR=0 ;;
            *)
                exit_on_error "Invalid value for COLOR. Must be \"yes\" or \"no\""
                ;;
        esac
    else
        # No terminal
        COLOR=0
    fi

    # Unset the strings last, because values for DRAFT or REMARKS
    # may have been altered in-between
    [[ "no" = $DRAFT ]] && unset DRAFT_STR
    [[ 0 -eq $META ]] && unset META_STR
    [[ 0 -eq $REMARKS ]] && unset REMARK_STR

}

###########################################################################
#
# RUN MAKE
#
# Set up log writing and verbosity
# and call make
#
###########################################################################
function call_make () {
    local CORE_NO DBSTYLE_VERS LOG_PIPE LOGFILE MAKE_BIN MAKE_OPTIONS
    local MAKE_CMD STRING SUB_CMD

    # first argument passed to the function is the subcommand
    # in some cases, additional arguments are passed to this
    # function - they remain in $@ and will be passed "as is" to make
    #
    SUB_CMD=$1
    shift

    # Check the remaining $@ - if it contains variable definitions (FOO=BAR
    # or FOO="BAR") it's OK, if it contains barewords, exit with an error
    #
    if [[ -n "$@" ]]; then
	for STRING in "$@"; do
	    [[ $STRING =~ ^[a-zA-Z][a-zA-Z0-9_]*=..* ]] || exit_on_error "Unknown parameter \"$STRING\"."
	done
    fi

    # set up the final environment
    init_env

    #------
    # the make command
    #

    MAKE_OPTIONS="-f $DAPSROOT/make/selector.mk"
    MAKE_BIN="/usr/bin/make"
    if [[ 1 = $DEBUG || 3 = $VERBOSITY ]]; then
        # use remake if installed when in debug or highest verbosity mode
        IS_REMAKE=$(which remake 2>/dev/null)
        [[ -n "$IS_REMAKE" ]] && MAKE_BIN="/usr/bin/remake"
        MAKE_OPTIONS="$MAKE_OPTIONS --debug=b"
    fi
    if [[ 0 = $VERBOSITY || 1 = $VERBOSITY || 2 = $VERBOSITY ]]; then
        # calculate Number of CPUs (cores) for -j option, set to "1" if empty
        CORE_NO=$(egrep -s -m1 "cpu cores\s*:" /proc/cpuinfo 2>/dev/null | sed 's/cpu cores\s*:\s*//')
        [[ -z "$CORE_NO" ]] && CORE_NO=1
        MAKE_OPTIONS="$MAKE_OPTIONS -j${CORE_NO}"
        [[ 1 != $DEBUG ]] && MAKE_OPTIONS="$MAKE_OPTIONS -s"
    else
        # highest verbosity level - use -j1 for a better readability
        MAKE_OPTIONS="$MAKE_OPTIONS -j1"
    fi

    # Is --force set to force a rebuild?
    [[ 1 = $FORCE_REBUILD ]] &&  MAKE_OPTIONS="$MAKE_OPTIONS --always-make"

    MAKE_CMD="$MAKE_BIN $MAKE_OPTIONS $SUB_CMD $@"


    # Variable settings summary printed on debug and high verbosity mode
    if [[ 2 -le $VERBOSITY ]]; then
	# get stylesheet version (ticket #151)
#	DBSTYLE_VERS=$($XSLTPROC --stylesheet $DAPSROOT/daps-xslt/common/get-dbxslt-version.xsl http://docbook.sourceforge.net/release/xsl/current/VERSION.xsl
        echo -e "---------------
           DOC_DIR: $DOC_DIR
         BUILD_DIR: $BUILD_DIR
          DAPSROOT: $DAPSROOT
           DOCCONF: $DOCCONF
              BOOK: $BOOK

"
        if [[ -n "$STYLEDEVEL" ]]; then
            echo "         STYLEROOT: $STYLEDEVEL"
        else
            if [[ -n "$STYLEROOT" ]]; then
                echo "         STYLEROOT: $STYLEROOT"
            else
                echo "         STYLEROOT: $DOCBOOK_STYLES"
            fi
        fi

        echo "FALLBACK_STYLEROOT: $FALLBACK_STYLEROOT
          EPUB_CSS: $EPUB_CSS
          HTML_CSS: $HTML_CSS

     PDF FORMATTER: $FORMATTER"
        if [[ "fop" = $FORMATTER ]]; then
            echo " FORMATTER WRAPPER: $FOP_WRAPPER
  FORMATTER CONFIG: $FOP_CONFIG_FILE"

        elif [[ "xep" = $FORMATTER ]]; then
            echo "  FORMATTER WRAPPER: $XEP_WRAPPER
  FORMATTER CONFIG: $XEP_CONFIG_FILE"
        fi
        echo "
           MAKECMD: $MAKE_CMD
     XSLTPROCESSOR: $XSLTPROCESSOR
 XML_CATALOG_FILES: $XML_CATALOG_FILES
---------------
"
    fi

    if [[ 1 = $WRITE_LOG ]]; then
        LOGFILE="${LOG_DIR}/make_${SUB_CMD}.log"
        date &> $LOGFILE
    fi

    if [[ 0 != $VERBOSITY ]]; then
#        echo ""
        $MAKE_CMD 2>&1 | tee -a $LOGFILE
        # see http://www.unix.com/shell-programming-scripting/92163-command-does-not-return-exit-status-due-tee.html
        [[ 0 = ${PIPESTATUS[0]} ]] || exit 1
    else
        if [[ 1 = $WRITE_LOG ]]; then
            $MAKE_CMD >> $LOGFILE 2>&1
            if [[ 0 = $? ]]; then
	        # make command successful, only show last line (aka result)
	        tail -n 1 $LOGFILE
            else
                # an error occured in make
                # show complete logfile except the first line containing the
                # date
	        tail -n +2 $LOGFILE
                exit 1
            fi
        else
           $MAKE_CMD
        fi
    fi
}

##########################################################
#
# FUNCTION TEMPLATE
#
##########################################################
#    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS

    # The subcommand value is passed when calling this function
#    SUB_CMD=$1
#    shift

    # SHORT_OPTS: Value for the getopt -o option
    # LONG_OPTS:  VALUE for the getopt -l option
#    SHORT_OPTS="h"
#    LONG_OPTS="draft,formatter:,help,name:,remarks,rootid:"

    # Call the argument parser
#    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"

    # Reset this functions $@ to what is remaining after having parsed the
    # subcommand switches
#    eval set -- "$P_REMAIN_ARGS"

#    #------ Computing the values returned from the parser -----

#    <REPLACE ME>

#    call_make "$UB_CMD" "$@"


###########################################################################
#
# BUILD PDFS
#
# Subcommand: pdf
#
###########################################################################
function build_pdfs () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="cropmarks,draft,formatter:,help,grayscale,meta,name:,remarks,rootid:,xsltparam:"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
	help_cropmarks
        help_draft
        help_formatter
	help_grayscale_pdf
        help_help
        help_meta
        help_name
        help_remarks
        help_rootid
        help_xsltparam "creates the .fo file from the profiled sources"
        echo
        exit 0
    fi

    [[ 1 = $P_DRAFT ]]      && DRAFT="yes"
    [[ 1 = $P_REMARKS ]]    && REMARKS=1
    # usemeta implies draft mode
    [[ 1 = $P_META ]]       && META=1 DRAFT="yes"
    [[ 1 = $P_CROPMARKS ]]  && export CROPMARKS=1
    [[ 1 = $P_GRAYSCALE ]]  && export GRAYSCALE=1
    [[ -n "$P_NAME" ]]      && export PDFNAME="$P_NAME" BOOK="$P_NAME"
    [[ -n "$P_ROOTID" ]]    && export ROOTID="$P_ROOTID"
    [[ -n "$P_XSLTPARAM" ]] && export XSLTPARAM="$P_XSLTPARAM"

    if [[ -n "$P_FORMATTER" ]]; then
        if [[ xep = $P_FORMATTER || fop = $P_FORMATTER ]]; then
            export FORMATTER="$P_FORMATTER"
        else
	    exit_on_error "Wrong parameter for --formatter: must be \"xep\" or \"fop\"!"
        fi
    fi

    call_make "$SUB_CMD" "$@"
}


###########################################################################
#
# BUILD HTML and JSP
#
# Subcommands: html
#
###########################################################################
function build_html_jsp () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="clean,css:,draft,help,html5,jsp,name:,meta,remarks,rootid:,single,statdir:,static,xsltparam:"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_clean
        help_css
        help_draft
        help_help
        help_html5
	help_jsp
        help_meta
        help_name
        help_remarks
        help_rootid
	help_single
        help_statdir
        help_static
        help_xsltparam "creates $SUB_CMD from the profiled sources"
        echo
        exit 0
    fi

    [[ 1 = $P_CLEAN ]]       && export CLEAN_DIR=1
    [[ -n "$P_CSS" ]]        && export HTML_CSS="$P_CSS"
    [[ 1 = $P_DRAFT ]]       && DRAFT="yes"
    [[ 1 = $P_REMARKS ]]     && REMARKS=1
    # usemeta implies draft mode
    [[ 1 = $P_META ]]        && META=1 DRAFT="yes"
    [[ 1 = $P_STATIC ]]      && export STATIC_HTML=1
    [[ 1 = $P_HTML5 ]]       && export HTML5=1
    [[ -n "$P_ROOTID" ]]     && export ROOTID="$P_ROOTID"
    [[ -n "$P_NAME" ]]       && export PDFNAME="$P_NAME" BOOK="$P_NAME"
    [[ -n "$P_STATIC_DIR" ]] && export STATIC_DIR="$P_STATIC_DIR"
    [[ -n "$P_XSLTPARAM" ]]  && export XSLTPARAM="$P_XSLTPARAM"

    if [[ 1 = $P_HTMLSINGLE && 1 = $P_JSP ]]; then
	exit_on_error "--single and --jsp are mutually exclusive"
    else
	[[ 1 = $P_HTMLSINGLE ]] && export HTMLSINGLE=1
	[[ 1 = $P_JSP ]]        && export JSP=1
    fi

    call_make "$SUB_CMD" "$@"
}

###########################################################################
#
# WEBHELP
#
# Subcommands: webhelp
#
###########################################################################
function webhelp () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="clean,css:,draft,help,name:,nosearch,remarks,rootid:,static,xsltparam:"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_clean
        help_css
        help_draft
        help_help
        help_name
        help_nosearch
        help_remarks
        help_rootid
        help_static
        help_xsltparam "creates Webhelp HTML from the profiled sources"
        echo
        exit 0
    fi

    if [[ ! -f $DOCBOOK_STYLES/extensions/webhelpindexer.jar && \
        ! -f $DOCBOOK_STYLES/extensions/lucene-analyzers-*.jar && \
        ! -f $DOCBOOK_STYLES/extensions/lucene-core-*.jar  && \
        ! -f $DOCBOOK_STYLES/extensions/tagsoup-*.jar ]]; then
        exit_on_error "\nwebhelp only works when a recent snapshot of the DocBook stylesheets is\ninstalled. Your version of the DocBook styles at\n$DOCBOOK_STYLES\nis not webhelp capable."
    fi

    [[ 1 = $P_CLEAN ]]    && export CLEAN_DIR=1
    [[ 1 = $P_DRAFT ]]    && DRAFT="yes"
    [[ 1 = $P_REMARKS ]]  && REMARKS=1
    [[ 1 = $P_STATIC ]]   && export STATIC_HTML=1
    [[ 1 = $P_NOSEARCH ]] && export WH_SEARCH="no"
    [[ -n "$P_ROOTID" ]]    && export ROOTID="$P_ROOTID"
    [[ -n "$P_NAME" ]]      && export PDFNAME="$P_NAME" BOOK="$P_NAME"
    [[ -n "$P_XSLTPARAM" ]] && export XSLTPARAM="$P_XSLTPARAM"

    if [[ -n "$P_CSS" ]]; then
        if [[ $P_CSS = "none" || -f "$P_CSS" ]]; then
            export HTML_CSS="$P_CSS"
        else
            exit_on_error "Cannot find CSS file $P_CSS (have you specified a correct path?)."
        fi
    fi

    call_make "$SUB_CMD" "$@"
}

###########################################################################
#
# BUILD ePUB
#
# Subcommands: epub only
#
###########################################################################
function build_epub () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="check,css:,epub3,help,name:,remarks,rootid:"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_check
        help_css
	help_epub3
        help_help
        help_name
        help_rootid
        echo
        exit 0
    fi

    [[ 1 = $P_REMARKS ]]  && REMARKS=1
    [[ 1 = $P_EPUB3 ]]  && EPUB3=1
    [[ -n "$P_NAME" ]]      && export PDFNAME="$P_NAME" BOOK="$P_NAME"
    [[ -n "$P_ROOTID" ]]    && export ROOTID="$P_ROOTID"

    # Checking ePUBs requires a minimum verbosity level of 1
    if [[ 1 = $P_CHECK ]]; then
        [[ 0 = $VERBOSITY ]] && export VERBOSITY=1
        export EPUBCHECK="yes"
    fi

    if [[ -n "$P_CSS" ]]; then
        if [[ $P_CSS = "none" || -f "$P_CSS" ]]; then
            export EPUB_CSS="$P_CSS"
        else
            exit_on_error "Cannot find CSS file $P_CSS (have you specified a correct path?)."
        fi
    fi

    call_make "$SUB_CMD" "$@"
}

###########################################################################
#
# BUILD man pages
#
# Subcommands: man only
#
###########################################################################
function build_man () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="help,nogzip,rootid:,subdirs"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_help
        help_nogzip
        help_rootid
        help_subdirs
        echo
        exit 0
    fi

    [[ -n "$P_NOGZIP" ]]    && export GZIP_MAN="no"
    [[ -n "$P_ROOTID" ]]    && export ROOTID="$P_ROOTID"
    [[ -n "$P_SUBDIRS" ]]   && export MAN_SUBDIRS="yes"

    call_make "$SUB_CMD" "$@"
}


###########################################################################
#
# Generic BUILD function
#
# Subcommands: every commands that does not fit elsewhere
#
###########################################################################
function build_generic () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="help,name:,rootid:"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_help
        help_name
        help_rootid
        echo
        exit 0
    fi

    [[ -n "$P_NAME" ]]      && export PDFNAME="$P_NAME" BOOK="$P_NAME"
    [[ -n "$P_ROOTID" ]]    && export ROOTID="$P_ROOTID"

    call_make "$SUB_CMD" "$@"
}

###########################################################################
#
# PACKAGING locdrop
#
# Subcommand: locdrop only
#
###########################################################################
function build_locdrop () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="def-file:,export-dir:,help,name:,nopdf,rootid:"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_def-file
        help_export-dir
        help_help
        help_name
        help_nopdf
        help_rootid
        echo
        exit 0
    fi

    [[ -n "$P_NAME" ]]      && export PDFNAME="$P_NAME" BOOK="$P_NAME"
    [[ -n "$P_NOPDF" ]]     && export export NOPDF=1
    [[ -n "$P_ROOTID" ]]    && export ROOTID="$P_ROOTID"
    [[ -n "$P_EXPORT_DIR" ]] && export LOCDROP_EXPORT_DIR="$P_EXPORT_DIR"

    if [[ -f $P_DEF_FILE ]]; then
        export DEF_FILE="$P_DEF_FILE"
    elif [[ -z "$P_DEF_FILE" ]]; then
	[[ 0 != $VERBOSITY ]] && ccecho "warn" "Warning: No DEF file was specified"
    else
        exit_on_error "Cannot find DEF file \"$P_DEF_FILE\""
    fi

    call_make "$SUB_CMD" "$@"
}

###########################################################################
#
#  PACKAGING online-docs
#
#  Subcommands: online-docs online-localized
#
###########################################################################
function online-docs () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="export-dir:,formatter:,help,name:,noepub,nohtml,nopdf,noset,rootid:"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_export-dir
        help_formatter
        help_help
        help_name
        help_noset
        help_rootid
        echo
        exit 0
    fi

    [[ -n "$P_NAME" ]]   && export PDFNAME="$P_NAME" BOOK="$P_NAME"
    [[ 1 = $P_NOEPUB ]]  && export NOEPUB=1
    [[ 1 = $P_NOHTML ]]  && export NOHTML=1
    [[ 1 = $P_NOPDF ]]   && export NOPDF=1
    [[ 1 = $P_NOSET ]]   && export NOSET=1
    [[ -n "$P_ROOTID" ]] && export ROOTID="$P_ROOTID"

    if [[ 1 = $P_NOHTML ]]; then
	export NOHTML=1
    else
	# online-docs always builds a single HTML file
	export HTMLSINGLE=1
    fi

    if [[ -n "$P_EXPORT_DIR" ]]; then
        if [[ -d $P_EXPORT_DIR ]]; then
            export OD_EXPORT_DIR="$P_EXPORT_DIR"
        else
            exit_on_error "Export directory \"P_EXPORT_DIR\"\ndoes not exist. Please create it first."
        fi
    fi
    if [[ -n "$P_FORMATTER" ]]; then
        if [[ xep = $P_FORMATTER || fop = $P_FORMATTER ]]; then
            export FORMATTER="$P_FORMATTER"
        else
	    exit_on_error "Wrong parameter for --formatter: must be \"xep\" or \"fop\"!"
        fi
    fi

    call_make "$SUB_CMD" "$@"
}

###########################################################################
#
#  PACKAGING package-src
#
#  Subcommands: package-src only
#
###########################################################################
function package-src () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="def-file:,help,name:,set-date:"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_def-file
        help_help
        help_name
        help_set-date
        echo
        exit 0
    fi

    [[ -n "$P_NAME" ]]      && export PDFNAME="$P_NAME" BOOK="$P_NAME"

    if [[ -n "$P_DEF_FILE" ]]; then
        if [[ -f $P_DEF_FILE ]]; then
            export DEF_FILE="$P_DEF_FILE"
        else
            exit_on_error "Cannot find DEF file \"$P_DEF_FILE\""
        fi
    else
       [[ 0 != $VERBOSITY ]] && ccecho "warn" "Warning: No DEF file was specified"
    fi

    if [[ -n "$P_SETDATE" ]]; then
        SETDATE=$(date -d "$P_SETDATE" +"%b %d %Y" 2>/dev/null) || exit_on_error "Wrong value for set-date: must be in a \"date\" compatible format,\ne.g. \"YYYY-MM-DD\"!"
        export SETDATE
    fi

    call_make "$SUB_CMD" "$@"
}

###########################################################################
#
#  PACKAGE PDF
#
#  Subcommand: package-pdf
#
###########################################################################
function package-pdf () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="cropmarks,desktopfiles,documentfiles,formatter:,grayscale,help,name:,pagefiles,rootid:,set-date:,xsltparam:"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_cropmarks
        help_desktopfiles
        help_documentfiles
        help_formatter
        help_grayscale_pdf
        help_help
        help_name
        help_pagefiles
        help_rootid
        help_set-date
        help_xsltparam "creates the .fo file from the profiled sources"
        echo
        exit 0
    fi

    [[ 1 = $P_DESKTOPFILES ]]  && export export DESKTOPFILES=1
    [[ 1 = $P_DOCUMENTFILES ]] && export export DOCUMENTFILES=1
    [[ 1 = $P_PAGEFILES ]]     && export export PAGEFILES=1
    [[ 1 = $P_CROPMARKS ]]     && export CROPMARKS=1
    [[ 1 = $P_GRAYSCALE ]]     && export GRAYSCALE=1
    [[ -n "$P_NAME" ]]         && export PDFNAME="$P_NAME" BOOK="$P_NAME"
    [[ -n "$P_ROOTID" ]]       && export ROOTID="$P_ROOTID"
    [[ -n "$P_XSLTPARAM" ]]    && export XSLTPARAM="$P_XSLTPARAM"

    if [[ -n "$P_FORMATTER" ]]; then
        if [[ xep = $P_FORMATTER || fop = $P_FORMATTER ]]; then
            export FORMATTER="$P_FORMATTER"
        else
	    exit_on_error "Wrong parameter for --formatter: must be \"xep\" or \"fop\"!"
        fi
    fi

    if [[ -n "$P_SETDATE" ]]; then
        SETDATE=$(date -d "$P_SETDATE" +"%b %d %Y" 2>/dev/null) || exit_on_error "Wrong value for set-date: must be in a \"date\" compatible format,\ne.g. \"YYYY-MM-DD\"!"
        export SETDATE
    fi

    call_make "$SUB_CMD" "$@"
}



###########################################################################
#
#  Package HTML
#
#  Subcommand: package-html
#
###########################################################################
function package-html () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="css:,desktopfiles,documentfiles,help,html5,jsp,name:,pagefiles,rootid:,set-date:,single,statdir:,xsltparam:"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_css
        help_desktopfiles
        help_documentfiles
        help_help
        help_html5
	help_jsp
        help_name
        help_pagefiles
        help_rootid
        help_set-date
	help_single
        help_statdir
        help_xsltparam "creates the .html files from the profiled sources"
	echo
        exit 0
    fi


    [[ 1 = $P_DESKTOPFILES ]]  && export export DESKTOPFILES=1
    [[ 1 = $P_DOCUMENTFILES ]] && export export DOCUMENTFILES=1
    [[ 1 = $P_PAGEFILES ]]     && export export PAGEFILES=1
    [[ 1 = $P_HTML5 ]]         && export HTML5=1
    [[ -n "$P_CSS" ]]          && export HTML_CSS="$P_CSS"
    [[ -n "$P_NAME" ]]         && export PDFNAME="$P_NAME" BOOK="$P_NAME"
    [[ -n "$P_ROOTID" ]]       && export ROOTID="$P_ROOTID"
    [[ -n "$P_STATIC_DIR" ]]   && export STATIC_DIR="$P_STATIC_DIR"
    [[ -n "$P_XSLTPARAM" ]]    && export XSLTPARAM="$P_XSLTPARAM"

    # We always want to start with a clean HTML result directory for
    # package-html
    #
    [[ "package-html" = $SUB_CMD ]] && export CLEAN_DIR=1

    if [[ 1 = $P_HTMLSINGLE && 1 = $P_JSP ]]; then
	exit_on_error "--single and --jsp are mutually exclusive"
    else
	[[ 1 = $P_HTMLSINGLE ]] && export HTMLSINGLE=1
	[[ 1 = $P_JSP ]]        && export JSP=1
    fi

    if [[ -n "$P_SETDATE" ]]; then
        SETDATE=$(date -d "$P_SETDATE" +"%b %d %Y" 2>/dev/null) || exit_on_error "Wrong value for set-date: must be in a \"date\" compatible format,\ne.g. \"YYYY-MM-DD\"!"
        export SETDATE
    fi

    call_make "$SUB_CMD" "$@"
}

###########################################################################
#
#  PROFILE First
#
#  Some subcommands (such as projectgraphics and various dist and packaging
#  targets) require an up-tp-date .profiled/*
#  Therefore we call make profile first and then call make a second time
#  with the real target
#
###########################################################################
function profile_first () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="draft,help,name:,remarks,rootid:"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_draft
        help_name
        help_remarks
        help_rootid
        echo
	exit 0
    fi

    [[ 1 = $P_DRAFT ]]    && DRAFT="yes"
    [[ 1 = $P_REMARKS ]]  && REMARKS=1
    [[ -n "$P_NAME" ]]      && export PDFNAME="$P_NAME" BOOK="$P_NAME"
    [[ -n "$P_ROOTID" ]]    && export ROOTID="$P_ROOTID"

    # we do not want to write a logfile this time
    WRITE_LOG=0
    call_make "profile" "$@" || exit_on_error "Profiling failed"
    call_make "$SUB_CMD" "$@"
}

###########################################################################
#
#  REMARKS
#
#  Subcommands validate and profiledir behave differently when
#  comments or remarks are enabled
#
###########################################################################
function comments_remarks () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="help,remarks"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_remarks
        echo
	exit 0
    fi

    [[ 1 = $P_REMARKS ]]  && REMARKS=1

    # we do not want to write a logfile this time
    WRITE_LOG=0
    call_make "$SUB_CMD" "$@"

}

###########################################################################
#
#  FILELISTS
#
#  Subcommands: list-files, list-srcfiles*, list-images-*
#
###########################################################################
function filelists () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="help,nodc,noent,noimg,noxml,pretty,rootid:"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_help
	if [[ $SUB_CMD =~ list-srcfiles ]]; then
            help_nodc
            help_noent
            help_noimg
            help_noxml
	fi
	[[ $SUB_CMD != list-file ]] && help_pretty
	help_rootid
        echo
        exit 0
    fi
    [[ 1 = $P_LIST_NODC ]]  && export LIST_NODC=1
    [[ 1 = $P_LIST_NOENT ]] && export LIST_NOENT=1
    [[ 1 = $P_LIST_NOIMG ]] && export LIST_NOIMG=1
    [[ 1 = $P_LIST_NOXML ]] && export LIST_NOXML=1
    [[ 1 = $P_PRETTY ]]     && export PRETTY_FILELIST=1
    [[ -n "$P_ROOTID" ]]    && export ROOTID="$P_ROOTID"

    if [[ $SUB_CMD = list-file && -z $ROOTID ]]; then
	exit_on_error "You need to specify an ID with --rootid with the list-file command."
    fi

    # we do not want to write a logfile this time
    WRITE_LOG=0
    call_make "$SUB_CMD" "$@"
}

###########################################################################
#
#  SHOW NAMES
#
#  function for all targets showing a filename or a directory
#  (pdf-name, htmlsingle-name, etc.)
#
###########################################################################

function show_names () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="cropmarks,draft,formatter:,grayscale,help,jsp,meta,name:,remarks,rootid:,single"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
                help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
		[[ "pdf-name" = $SUB_CMD ]] && help_cropmarks
                help_draft
		[[ "pdf-name" = $SUB_CMD ]] && help_formatter
		[[ "pdf-name" = $SUB_CMD ]] && help_grayscale_pdf
                help_help
		[[ "jsp-dir-name" =  $SUB_CMD ]] && help_jsp
		help_meta
                help_name
                help_remarks
                help_rootid
		[[ "html-dir-name" = $SUB_CMD ]] && help_single
                echo
                exit 0
    fi

    [[ 1 = $P_DRAFT ]]      && DRAFT="yes"
    [[ 1 = $P_REMARKS ]]    && REMARKS=1
    # usemeta implies draft mode
    [[ 1 = $P_META ]]       && META=1 DRAFT="yes"
    [[ 1 = $P_CROPMARKS ]]  && export CROPMARKS=1
    [[ 1 = $P_GRAYSCALE ]]  && export GRAYSCALE=1
    [[ -n "$P_ROOTID" ]]    && export ROOTID="$P_ROOTID"
    [[ -n "$P_NAME" ]]      && export PDFNAME="$P_NAME" BOOK="$P_NAME"

    if [[ 1 = $P_HTMLSINGLE && 1 = $P_JSP ]]; then
	exit_on_error "--single and --jsp are mutually exclusive"
    else
	[[ 1 = $P_HTMLSINGLE ]] && export HTMLSINGLE=1
	[[ 1 = $P_JSP ]]        && export JSP=1
    fi

    if [[ -n "$P_FORMATTER" ]]; then
        if [[ xep = $P_FORMATTER || fop = $P_FORMATTER ]]; then
            export FORMATTER="$P_FORMATTER"
        else
	    exit_on_error "Wrong parameter for --formatter: must be \"xep\" or \"fop\"!"
        fi
    fi

    # we do not want to write a logfile this time
    WRITE_LOG=0
    call_make "$SUB_CMD" "$@"
}

###########################################################################
#
#  CHECKLINK
#
#  checks http links in file or from rootid
#
###########################################################################

function checklink () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS

    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="file:,help,rootid:,show"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_file
        help_help
        help_rootid
	help_show_check
        echo -e "    NOTES: * Options --file (-f) and --rootid exclude one another.\n           * If neither file nor rootid is specified, the rootid\n             from the DC-file is used\n           * $SUB_CMD follows xi:includes\n"
	exit 0
    fi

    if [[ -z "$P_ROOTID" && -z "$P_FILE" ]]; then
        if [[ 0 != $VERBOSITY ]]; then
            ccecho "info" "Neither file nor rootid specified, using rootid from DC-file"
        fi
    elif [[ -n "$P_ROOTID" && -n "$P_FILE" ]]; then
        exit_on_error "Options --file (-f) and --rootid exclude one another.\nPlease specify only one of these options"
    fi

    [[ -n "$P_ROOTID" ]]    && export ROOTID="$P_ROOTID"
    [[ -n "$P_SHOW" ]]      && export SHOW=1

    if [[ -n "$P_FILE" ]]; then
        if [[ -f $P_FILE ]]; then
            export ROOTID=$($XSLTPROC --stylesheet $DAPSROOT/daps-xslt/common/get-rootelement-id.xsl --file $P_FILE $XSLTPROCESSOR) || exit_on_error "Cannot get a rootid from file $FILE"
        else
           exit_on_error "File $P_FILE does not exist"
        fi
    fi

    call_make "$SUB_CMD" "$@"
}

###########################################################################
#
#  GETIMAGES
#
#  Gets a list of images from the file specified with -f or --file or
#  the document specified by rootid  and outputs them as:
#   * default:       long list (one file per line)
#   * --compact:  compact list (single line)
#   * --viewer=VIEWER: shows images in VIEWER and prints long list to STDOUT
#
#  the additional option (--modified) will also print the image file's
#  mtime in long lists (this option is ignored with --compact)
#
###########################################################################
function getimages () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    local COMPACT DEBUG_SAV FILE IMAGEDIR MOD P_FILE
    local PROFDIR SHOW VERBOSITY_SAV
    local -a IMGLIST

    SUB_CMD=$1
    shift

    IMAGEDIR="$DOC_DIR/images/src/"

    # any kind of verbosity is unwanted in this case
    WRITE_LOG=0
    DEBUG=0
    VERBOSITY=0

    SHORT_OPTS="h"
    LONG_OPTS="compact,file:,help,modified,rootid:,show,viewer:"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_compact
        help_file
        help_modified
        help_rootid
        help_show_images
        help_viewer
        echo -e "    NOTES: * Options --file (-f) and --rootid exclude one another.\n           * If neither file nor rootid is specified, the rootid\n             from the DC-file is used\n           * $SUB_CMD follows xi:includes\n"
	exit 0
    fi

    [[ 1 = $P_COMPACT ]]  && COMPACT=1
    [[ 1 = $P_MODIFIED ]] && MOD=1
    [[ 1 = $P_SHOW ]]     && SHOW=1
    [[ -n "$P_VIEWER" ]] && IMG_VIEWER="$P_VIEWER"

    # set ROOTID - either directly or via $FILE
    if [[ -z "$P_ROOTID" && -z "$P_FILE" ]]; then
        if [[ 0 != $VERBOSITY ]]; then
            ccecho "info" "Neither file nor rootid specified, using rootid from DC-file"
        fi
    elif [[ -n "$P_ROOTID" && -n "$P_FILE" ]]; then
        exit_on_error "Options --file (-f) and --rootid exclude one another.\nPlease specify only one of these options"
    fi

    [[ -n "$P_ROOTID" ]]    && export ROOTID="$P_ROOTID"

    if [[ -n $P_FILE ]]; then
        if [[ -f $P_FILE ]]; then
            export ROOTID=$($XSLTPROC --stylesheet $DAPSROOT/daps-xslt/common/get-rootelement-id.xsl --file $P_FILE $XSLTPROCESSOR) || exit_on_error "Cannot get a rootid from file $FILE"
        else
           exit_on_error "File $P_FILE does not exist"
        fi
    fi

    # IMG_VIEWER may also be set via config file:
    if [[ $SHOW ]]; then
        if [[ -z "$IMG_VIEWER" ]]; then
            exit_on_error "Please specify an image viewer via command-line (--viewer) or via config file"
        else
            IMG_VIEWER=$(which $IMG_VIEWER 2>/dev/null)
            if [[ 0 < $? ]]; then # which command failed
                # Viewer was specified on command-line
                if [[ $P_VIEWER ]]; then
                    exit_on_error "Cannot find VIEWER $CMD_IMG_VIEWER"
                # Viewer was specified via config
                else
                    exit_on_error "Cannot find VIEWER $IMG_VIEWER. Please check your config file"
                fi
            fi
        fi
    fi

    # get the image list
    # we can use projectgraphics, since it returns images for a given rootid
    IMGLIST=( $(call_make list-srcfiles LIST_NODC=1 LIST_NOENT=1 LIST_NOXML=1) )
    if [[ 0 != $? ]]; then
        exit_on_error "Failed to get list of images"
    fi

    if [[ 0 < ${#IMGLIST[@]} ]]; then
        if [[ $COMPACT ]]; then
            echo -e "${IMGLIST[@]}\n"
        else
            for IMAGE in ${IMGLIST[@]}; do
                if [[ $MOD ]]; then
	            MODIFIED=$(stat -c %y ${IMAGE} | cut -d '.' -f1)
	            echo "${IMAGE} (${MODIFIED})"
                else
	            echo "${IMAGE}"
                fi
            done  | column -t
            if [[ $SHOW ]]; then
                $IMG_VIEWER ${IMGLIST[@]} &
            fi
        fi
    fi
    exit
}

###########################################################################
#
#  SPELLCHECK
#
#  Spellchecks a file specified with -f or --file or
#  the document specified by rootid.
#
###########################################################################
function spellcheck () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    local COUNT FILE LISTMODE LISTOUTPUT SPELLCMD
    local -a FILELIST SKIPLIST

    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="extra-dict:,file:,help,lang:,list,rootid:"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_extra-dict
        help_file
        help_help
        help_lang
        help_list
        help_rootid
        echo -e "    NOTES: * Options --file (-f) and --rootid exclude one another.\n           * If neither file nor rootid is specified, the rootid\n             from the DC-file is used\n           * $SUB_CMD follows xi:includes\n"
	exit 0
    fi

    [[ -n "$P_FILE" ]] && FILELIST[0]="$P_FILE"
    [[ 1 = $P_LIST ]] && LISTMODE=1

    # extra dictionary
    # check and absolutize path
    if [[ -n "$P_ASPELL_EXTRA_DICT" ]]; then
        if [[ -e $P_ASPELL_EXTRA_DICT ]]; then
            sanitize_path "$P_ASPELL_EXTRA_DICT" "ASPELL_EXTRA_DICT"
        else
            exit_on_error "Path to extra dictionary \"$P_ASPELL_EXTRA_DICT\" is not valid"
        fi
    fi

    # set FILELIST if rootid was specified
    if [[ -z "$P_ROOTID" && -z "$P_FILE" ]]; then
        if [[ 0 != $VERBOSITY ]]; then
            ccecho "info" "Neither file nor rootid specified, using rootid from DC-file"
        fi
    elif [[ -n "$P_ROOTID" && -n "$P_FILE" ]]; then
        exit_on_error "Options --file and --rootid exclude one another.\nPlease specify only one of these options"
    fi

    [[ -n "$P_ROOTID" ]] && export ROOTID="$P_ROOTID"

    if [[ -z "${FILELIST[0]}" ]]; then ## --file was not specified
        FILELIST=( $(call_make list-srcfiles LIST_NODC=1 LIST_NOENT=1 LIST_NOIMG=1 ) )
        if [[ 0 != $? ]]; then
            exit_on_error "Failed to get filelist for ROOTID \"$ROOTID\""
        fi
    fi

    # Set language - if not specified try to get from $MAIN
    #
    if [[ -n "$P_LANG" ]]; then
        ASPELL_LANG="$P_LANG"
    else
        ASPELL_LANG=$($XSLTPROC --stylesheet ${DAPSROOT}/daps-xslt/common/get-language.xsl --file $MAIN $XSLTPROCESSOR 2>/dev/null)
        if [[ -n "$ASPELL_LANG" ]]; then
            ccecho "info" "Using language $ASPELL_LANG."
        else
            exit_on_error "Failed to get language from $MAIN. Please specify it with --lang."
        fi
    fi

    #------------------
    # create spellchecking command
    #
    # first, create skiplist
    #
    COUNT=0
    for SKIP in ${ASPELL_SKIP_TAGS[@]}; do
        SKIPLIST[$COUNT]="--add-sgml-skip=$SKIP"
        let COUNT++
    done
    # now create the command
    SPELLCMD="/usr/bin/aspell --mode=sgml ${SKIPLIST[@]} --encoding=utf-8 --lang=$ASPELL_LANG"
    if [[ -n "$ASPELL_EXTRA_DICT" ]]; then
        SPELLCMD="$SPELLCMD --extra-dicts=$ASPELL_EXTRA_DICT"
    fi

    # do spellchecking on the list of files
    for FILE in ${FILELIST[@]}; do
        test -f $FILE || ccecho "warn" "File $FILE does not exist"
        if [[ 1 = $LISTMODE ]]; then
            LISTOUTPUT=$($SPELLCMD list < $FILE | sort -u)
            [[ -n "$LISTOUTPUT" ]] && echo -e "$FILE\n------------------------------\n$LISTOUTPUT\n"
            LISTOUTPUT=""
        else
            echo "Checking $FILE..."
            $SPELLCMD -c $FILE
        fi
    done
    exit
}

###########################################################################
#
# Stylecheck
#
# Performs a stylecheck on rootid
#
###########################################################################
function stylecheck    () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="file:,help,name:,rootid:,show"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
	help_file
        help_help
        help_name
        help_rootid
	help_show_check
        echo -e "    NOTES: * Options --file (-f) and --rootid exclude one another.\n           * If neither file nor rootid is specified, the rootid\n             from the DC-file is used\n           * $SUB_CMD follows xi:includes\n"
        exit 0
    fi

    if [[ -z "$P_ROOTID" && -z "$P_FILE" ]]; then
        if [[ 0 != $VERBOSITY ]]; then
            ccecho "info" "Neither file nor rootid specified, using rootid from DC-file"
        fi
    elif [[ -n "$P_ROOTID" && -n "$P_FILE" ]]; then
        exit_on_error "Options --file (-f) and --rootid exclude one another.\nPlease specify only one of these options"
    fi

    [[ -n "$P_NAME" ]]      && export PDFNAME="$P_NAME" BOOK="$P_NAME"
    [[ -n "$P_ROOTID" ]]    && export ROOTID="$P_ROOTID"
    [[ -n "$P_SHOW" ]]      && export SHOW=1

    if [[ -n "$P_FILE" ]]; then
        if [[ -f $P_FILE ]]; then
            export ROOTID=$($XSLTPROC --stylesheet $DAPSROOT/daps-xslt/common/get-rootelement-id.xsl --file $P_FILE $XSLTPROCESSOR) || exit_on_error "Cannot get a rootid from file $FILE"
        else
           exit_on_error "File $P_FILE does not exist"
        fi
    fi

    call_make "$SUB_CMD" "$@"
}


###########################################################################
#
# Debugging function
#
# Subcommands: dapsenv, nothing, showvariable
#
###########################################################################
function debugging () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="help,name:,rootid:,target:"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_help
        help_name
        help_rootid
        help_target
        echo
        exit 0
    fi

    [[ -n "$P_NAME" ]]      && export PDFNAME="$P_NAME" BOOK="$P_NAME"
    [[ -n "$P_ROOTID" ]]    && export ROOTID="$P_ROOTID"
    [[ -n "$P_TARGET" ]]    && export TARGET="$P_TARGET"

    call_make "$SUB_CMD" "$@"
}

###########################################################################
#
#  IMAGES
#
#  Generate images. For debugging and testing purposes
#
###########################################################################

function build_images () {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="color,gen,grayscale,online,rootid:"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD"
        help_color
        help_gen
        help_grayscale_images
        help_help
	help_online
	help_rootid
        echo
        exit 0
    fi

    if [[ -z "$P_COLOR" && -z "$P_IMAGES_GEN" && -z "$P_GRAYSCALE" && -z "$P_IMAGES_ONLINE" ]]; then
	export IMAGES_ALL=1
    else
	[[ -n "$P_COLOR" ]]            && export IMAGES_COLOR=1
	[[ -n "$P_IMAGES_GEN" ]]       && export IMAGES_GEN=1
	[[ -n "$P_GRAYSCALE" ]]        && export IMAGES_GRAYSCALE=1
	[[ -n "$P_IMAGES_ONLINE" ]]    && export IMAGES_ONLINE=1
    fi

    [[ -n "$P_ROOTID" ]]           && export ROOTID="$P_ROOTID"

    call_make "$SUB_CMD" "$@"
}


###########################################################################
#
#  MISC
#
#  various functions
#
###########################################################################

# call make directly
# for functions with no command line options
# do not write a log
function no_opts {
    local SHORT_OPTS LONG_OPTS SUB_CMD REMAIN_ARGS
    local SUB_CMD=$1
    shift

    SHORT_OPTS="h"
    LONG_OPTS="help"

    parse_args $SHORT_OPTS $LONG_OPTS $SUB_CMD "$@"
    eval set -- "$P_REMAIN_ARGS"

    #------ Computing the values returned from the parser -----
    if [[ 1 = $P_HELP ]]; then
        help_scmd_head "$SUB_CMD" "$HELP_SUBCMD" "0"
        exit 0
    fi

    WRITE_LOG=0
    call_make "$SUB_CMD" "$@"
}

# error message for deprecated targets
function deprecated {
    local SUB_CMD=$1
    ccecho "error" "$HELP_SUBCMD"
    exit 1
}


# error message when specifying an invalid subcommand
function wrong_parameter () {
    local SUB_CMD=$1
    echo "Type '$ME $SUB_CMD help' to get a list of valid parameters"
    exit 1;
}

# needed by docmanager
function showenv {
    echo "DOC_DIR=$DOC_DIR;DOCCONF=$DOCCONF"
    exit 0
}

###########################################################################
#
# HELP
#
# There are a lot of options, several functions have in common.
# In order to not have to write the same text again and again, we
# provide a help function for each option
#
###########################################################################

# first line of help
#
function help_scmd_head () {
    echo -e "
$ME [--global-options] $1 [options]

$2
"
[[ 0 != $3 ]] && echo -e "  Command options:"
}

function help_check () {
    echo "    --check                   Validate the resulting ePUB document.
                              Useful when developing stylesheets. Implies a verbosity
                              level of at least 1.
                              Default: unset"
}
function help_clean () {
    echo "    --clean                   Clean up the result directory (delete all files and
                              subdirectories) before building the document.
                              Default: unset"
}
function help_color () {
    echo "    --color                   Only generate color images.
                              Default: off"
}
function help_compact () {
    echo "    --compact                 Print the filelist on a single line.
                              Ignored when -s|--show is set.
                              Default: off"
}
function help_cropmarks () {
    echo "    --cropmarks               Add cropmarks to the PDF. Only available for
                              the XEP formatter, FOP currently does not support
                              cropmarks.
                              Ignored when FOP is used.
                              Default: off"
}
function help_css () {
    echo "    --css=filename,           Specify a path to a css file.
              --css=none      The special string \"none\" forces DAPS to use
                              no css, even when configured elsewhere
                              (e.g. in a config file).
                              Default: unset"
}
function help_draft () {
    echo "    --draft                   Add a 'DRAFT' watermark to all pages of the book
                              Default: off"
}
function help_def-file () {
    echo "    --def-file=FILE           Specify a DEF-* file containing build
                              information"
}
function help_desktopfiles () {
    echo "    --desktopfiles            Generate .desktop files.
                              Default: off"
}
function help_documentfiles () {
    echo "    --documentfiles           Generate .document files.
                              Default: off"
}
function help_epub3 () {
    echo "    --epub3                   Generate ePUB version 3 eBooks.
                              Default: ePUB version 2"
}
function help_export-dir () {
    echo "    --export-dir=DIRECTORY    Specify a directory where to copy the results
                              of the $TARGET command. The directory will be
                              created if it does not exist.
                              Default: <BUILD_DIRECTORY>/online-docs"
}
function help_extra-dict () {
    echo "    --extra-dict=filename     Specify a path to an additional custom dictionary.
                              Default: unset"
}
function help_file () {
    echo "    --file=FILE               Specify the filename of an XML file"
}
function help_formatter () {
    echo "    --formatter=FORMATTER     Specify the PDF formatter to be used. Currently
                              'xep' or 'fop' are supported.
                              Default: 'fop'"
}
function help_gen () {
    echo "    --gen                     Do all image conversions (images/gen) but
                              do not generate or link the images to
                              images/color or images/grayscale.
                              Default: unset"
}
function help_grayscale_images () {
    echo "    --grayscale               Only generate grayscale images.
                              Default: off"
}
function help_grayscale_pdf () {
    echo "    --grayscale               Generate a grayscale PDF for printing.
                              Default: off"
}
function help_help () {
    echo "    --help, -h                Print this help text"
}
function help_html5 () {
    echo "    --html5                   HTML builds are generated as XHTML files.
                              Force HTML5 with this switch.
                              Default: unset"
}
function help_jsp () {
    echo "    --jsp                     Creates JSP output. Requires custom stylesheets
                              (not available with the standard DocBook
                              stylesheets).
                              Default: off"
}
function help_lang () {
    echo "    --lang                    Specify a language to use for spellchecking.
                              See \"man aspell \" for details.
                              Default: en_US"
}
function help_list () {
    echo "    --list                    Dumps a sorted list of misspelled words to
                              standard output instead of starting the
                              interactive spellchecker.
                              Default: en_US"
}
function help_meta () {
    echo "    --meta                    If set, prints additional status information
                              (filename, maintainer and status) for each file.
                              Implies draft mode.
                              Default: off"
}
function help_modified () {
    echo "    --modified                Print the image's modification time.
                              Ignored when --compact is set.
                              Default: off"
}
function help_name () {
    echo "    --name=BOOKNAME           File- and directory names for generated content
                              are derived from BOOKNAME.
                              Default: generated by stripping 'DC-' from the
                              doc config filename"
}
function help_nodc () {
    echo "    --nodc                    Exclude DC-file from list.
                              Default: unset"
}
function help_noent () {
    echo "    --noent                   Exclude Entity files from list.
                              Default: unset"
}
function help_nogzip () {
    echo "    --nogzip                  If specified, man pages will not be compressed
                              with gzip.
                              Default: unset"
}
function help_noimg () {
    echo "    --noimg                   Exclude images from list.
                              Default: unset"
}
function help_nohelp () {
    echo "
No further help for subcommand \"$1\" available.
"
}
function help_nopdf () {
    echo "    --nopdf                   Deactivates creating the color-pdf. Useful when
                              \"locdropping\" a complete set where you
                              want to deliver separate PDFs for each book
                              rather than one huge PDF for the whole set.
                              Default: off"
}
function help_nosearch () {
    echo "    --nosearch                Deactivates creating the search tab in webhtml
                              builds.
                              Default: enabled"
}
function help_noset () {
    echo "    --noset                   Creates a bigfile for the given book (specified
                              by the rootid) rather than the complete set.
                              Links in the bigfile that point to external
                              targets, are replaced by text-only pointers.
                              Default: off"
}
function help_noxml () {
    echo "    --noxml                   Exclude XML files from list.
                              Default: unset"
}
function help_online () {
    echo "    --online                  Only generate images used for HTML builds.
                              Default: off"
}
function help_pagefiles () {
    echo "    --pagefiles               Generate .page files.
                              Default: off"
}
function help_pretty () {
    echo "    --pretty                  Pretty print file lists (one filename per line)"
}
function help_remarks () {
    echo "    --remarks                 Include remarks (<remark>...</remark>) in book
                              Implies draft mode.
                              Default: off"
}
function help_rootid () {
    echo "    --rootid=ID               Specify a ROOTID to build only parts of a book
                              (parts or chapters). Default: Usually set
                              in the DC-file; if not set the complete set
                              defined in \$MAIN will be built"
}
function help_set-date () {
    echo "    --set-date=YYYY/MM/DD     Set a publication date. If not set, the current
                              date will automatically be chosen.
                              Default: current date"
}
function help_show_images () {
    echo "    --show                    Show images with an image viewer that either
                              has been specified with --viewer or by setting
                              IMG_VIEWER in the config file
                              Default: off"
}
function help_show_check () {
    echo "    --show                    Show the result of the check command
                              in a browser. Uses \$BROWSER if defined,
                              otherwise xdg-open.
                              Default: off"
}
function help_single () {
    echo "    --single                  Creates a single file HTML output (opposed to
                              the default, which generates chunked HTML,
                              consisting of several HTML pages.
                              Default: off"
}
function help_statdir () {
    echo "    --statdir=DIRECTORY       Specify a DIRECTORY containing resource files
                              (CSS, images, Javascript etc.).
                              DEFAULT: \$STYLEROOT/static"
}
function help_static () {
    echo "    --static                  Normally images and css files in HTML builds
                              are linked from elsewhere in the file system.
                              Use this option to copy these files in order
                              to create a distributable HTML build"
}
function help_subdirs () {
    echo "    --subdirs                 Man pages are created in a man/ directory.
                              To also enable the subdirectories man1/, man2/,
                              etc., specify this parameter.
                              Default: off"
}
function help_target () {
    echo "    --target=TARGET           Specify a potential target (such as jsp or
                              color-pdf) in order to retrieve correct values for
                              target-specific values.
                              Default: same as daps subcommand"
}
function help_viewer () {
    echo "    --viewer=VIEWER           Image viewer to be used.
                              Default: IMG_VIEWER setting from config file"
}
function help_xsltparam () {
    echo "    --xsltparam=STRING        Add one or more xslt processor parameters in
                              the form of
                              \"'--stringparam KEY=VALUE' --param KEY=VALUE\".
                              The given string will be passed unmodified to the
                              xslt processor call that
                              $1.
                              Useful to temporarily overwrite style sheet
                              parameters such as margins.
                              Note: You MUST quote the string with double and
                              single quotes: --xsltparam=\"'STRING'\"
                              Default: unset"
}
