#!/bin/sh
# yelp-build
# Copyright (C) 2010 Shaun McCance <shaunm@gnome.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

xsl_mal_cache='/usr/local/share/yelp-xsl/xslt/mallard/cache/mal-cache.xsl'
xsl_db2html='/usr/local/share/yelp-xsl/xslt/docbook/html/db2html.xsl'
xsl_db2xhtml='/usr/local/share/yelp-xsl/xslt/docbook/html/db2xhtml.xsl'
xsl_mal2html='/usr/local/share/yelp-xsl/xslt/mallard/html/mal2html.xsl'
xsl_mal2xhtml='/usr/local/share/yelp-xsl/xslt/mallard/html/mal2xhtml.xsl'
yelp_icon_dir='/usr/local/share/yelp-xsl/icons/hicolor/24x24/status'
yelp_js_dir='/usr/local/share/yelp-xsl/js'
xsl_mal_epub='/usr/local/share/yelp-tools/xslt/mal-epub.xsl'
xsl_mal_opf='/usr/local/share/yelp-tools/xslt/mal-opf.xsl'
xsl_mal_ncx='/usr/local/share/yelp-tools/xslt/mal-ncx.xsl'

mkdir_p () {
    if [ ! -d "$1" ]; then
        mkdir_p `dirname "$1"`
        mkdir "$1"
    fi
}

urlencode () {
    LANG=C awk '
BEGIN {
  for (i = 1; i <= 255; i++) chars[sprintf("%c", i)] = i;
}
{
  ret = "";
  for (i = 1; i <= length($0); i++) {
    c = substr($0, i, 1);
    if (c ~ /[\/a-zA-Z0-9._-]/)
      ret = ret c;
    else
      ret = ret sprintf("%%%X%X", int(chars[c] / 16), chars[c] % 16);
  }
  print ret;
}'
}

urldecode () {
    LANG=C awk '
BEGIN {
  for(i = 0; i < 10; i++) hex[i] = i;
  hex["A"] = hex["a"] = 10;
  hex["B"] = hex["b"] = 11;
  hex["C"] = hex["c"] = 12;
  hex["D"] = hex["d"] = 13;
  hex["E"] = hex["e"] = 14;
  hex["F"] = hex["f"] = 15;
}
{
  ret = "";
  for (i = 1; i <= length($0); i++) {
    c = substr($0, i, 1);
    if (c == "+") {
      ret = ret " ";
    }
    else if (c == "%") {
      c = sprintf("%c", hex[substr($0, i + 1, 1)] * 16 + hex[substr($0, i + 2, 1)]);
      ret = ret c;
      i += 2;
    }
    else {
      ret = ret c;
    }
  }
  print ret;
}'
}

yelp_usage () {
    (
        echo "Usage: yelp-build <COMMAND> [OPTIONS] [FILES]"
        echo ""
        echo "Commands:"
        echo "  cache         Create a Mallard cache file"
        echo "  epub          Create an EPUB file for Mallard"
        echo "  html          Convert input files to HTML"
        echo "  xhtml         Convert input files to XHTML"
    ) 1>&2
}
yelp_usage_cache () {
    (
        echo "Usage: yelp-build cache <FILES>"
        echo ""
        echo "  Create a Mallard cache file from the page files FILES."
        echo "  If FILES contains directories, all .page files in those"
        echo "  directories will be used."
        echo ""
        echo "Options:"
        echo "  -o OUT        Output cache to the file OUT"
    ) 1>&2
}
yelp_usage_epub () {
    (
        echo "Usage: yelp-build epub [OPTIONS] <FILES>"
        echo ""
        echo "  Create and EPUB file from the Mallard page files FILES."
        echo ""
        echo "Options:"
        echo "  -c CACHE      Use the existing Mallard cache CACHE"
        echo "  -o OUT        Output en EPUB file named OUT"
        echo "  -x CUSTOM     Import the custom XSLT file CUSTOM"
    ) 1>&2
}
yelp_usage_html () {
    (
        echo "Usage: yelp-build <html|xhtml> [OPTIONS] <FILES>"
        echo ""
        echo "  Create HTML or XHTML from the input files FILES."
        echo "  FILES can be DocBook files, Mallard page files,"
        echo "  or directories containing Mallard page files."
        echo ""
        echo "Options:"
        echo "  -c CACHE      Use the existing Mallard cache CACHE"
        echo "  -o OUT        Output files in the directory OUT"
        echo "  -x CUSTOM     Import the custom XSLT file CUSTOM"
    ) 1>&2
}

if [ $# = 0 ]; then
    yelp_usage
    exit 1
fi

yelp_cache_in () {
    echo '<cache:cache xmlns:cache="http://projectmallard.org/cache/1.0/"'
    echo '  xmlns="http://projectmallard.org/1.0/">'
    for page in "$@"; do
        if [ -d "$page" ]; then
            for sub in "$page"/*.page; do
                fbase=`basename "$sub"`
                fdir=`dirname "$sub"`
                fdir=`(cd "$fdir" && pwd)`
                echo "$fdir/$fbase"
            done
        else
            fbase=`basename "$page"`
            fdir=`dirname "$page"`
            fdir=`(cd "$fdir" && pwd)`
            echo "$fdir/$fbase"
        fi
    done | urlencode |
    while read line; do
        echo '<page cache:href="file://'"$line"'"/>'
    done
    echo '</cache:cache>'
}
yelp_cache () {
    cache_out="index.cache"
    while [ "$#" != "0" ]; do
        case "$1" in
            "-o")
                shift
                cache_out="$1"
                shift
                ;;
            *)
                break
                ;;
        esac
    done
    if [ "$#" = "0" -o "x$1" = "x--help" ]; then
        yelp_usage_cache
        exit 1
    fi
    yelp_cache_in "$@" | xsltproc --xinclude -o "$cache_out" "$xsl_mal_cache" -
}

yelp_html_xsl_common () {
    if [ "x$html_internal_datadir" != "x" ]; then
        echo '<xsl:variable name="yelp.internal.datadir" select="'"'$html_internal_datadir'"'"/>'
        echo '<xsl:param name="html.css.root" select="$yelp.internal.datadir"/>'
        echo '<xsl:param name="html.js.root" select="$yelp.internal.datadir"/>'
    else
        echo '<xsl:variable name="yelp.internal.datadir" select="'"''"'"/>'
    fi
    if [ "x$html_internal_xsl" != "x" ]; then
        echo '<xsl:include href="file://'`echo "$html_internal_xsl" | urlencode`'"/>'
    fi
    if [ "x$html_custom" != "x" ]; then
        echo '<xsl:include href="file://'`echo "$html_custom" | urlencode`'"/>'
    fi
    echo '<xsl:variable name="yelp.locale">'
    echo ' <xsl:choose>'
    echo '  <xsl:when test="$l10n.locale != '"''"'">'
    echo '   <xsl:value-of select="$l10n.locale"/>'
    echo '  </xsl:when>'
    echo '  <xsl:otherwise>'
    echo '   <xsl:text>C</xsl:text>'
    echo '  </xsl:otherwise>'
    echo ' </xsl:choose>'
    echo '</xsl:variable>'
    echo '<xsl:template name="html.css">'
    echo ' <xsl:param name="node" select="."/>'
    echo ' <exsl:document href="{$yelp.internal.datadir}{$yelp.locale}.css" method="text">'
    echo '  <xsl:call-template name="html.css.content">'
    echo '   <xsl:with-param name="node" select="$node"/>'
    echo '  </xsl:call-template>'
    echo ' </exsl:document>'
    echo ' <link rel="stylesheet" type="text/css" href="{$html.css.root}{$yelp.locale}.css"/>'
    echo '</xsl:template>'
    echo '<xsl:template name="html.js">'
    echo ' <xsl:param name="node" select="."/>'
    echo ' <xsl:call-template name="html.js.jquery">'
    echo '  <xsl:with-param name="node" select="$node"/>'
    echo ' </xsl:call-template>'
    echo ' <exsl:document href="{$yelp.internal.datadir}yelp.js" method="text">'
    echo '  <xsl:call-template name="html.js.content">'
    echo '   <xsl:with-param name="node" select="$node"/>'
    echo '  </xsl:call-template>'
    echo ' </exsl:document>'
    echo ' <script type="text/javascript" src="{$html.js.root}yelp.js"/>'
    echo '</xsl:template>'
}
yelp_html_db2html () {
    for xml in "$@"; do
        xmldir=`dirname "$xml"`
        xmldir=`(cd "$xmldir" && pwd)`
        # Output HTML
        (
            echo '<xsl:stylesheet'
            echo ' xmlns:xsl="http://www.w3.org/1999/XSL/Transform"'
            echo ' xmlns:exsl="http://exslt.org/common"'
            echo ' xmlns="http://www.w3.org/1999/xhtml"'
            echo ' extension-element-prefixes="exsl"'
            echo ' version="1.0">'
            if [ "x$is_xhtml" = "x1" ]; then
                xsl='file://'`echo "$xsl_db2xhtml" | urlencode`
            else
                xsl='file://'`echo "$xsl_db2html" | urlencode`
            fi
            echo '<xsl:import href="'"$xsl"'"/>'
            yelp_html_xsl_common
            echo '</xsl:stylesheet>'
        ) | xsltproc --xinclude -o "$html_out"/ - "$xml"
        # Copy media
        if [ "x$xmldir" != "x$html_out" ]; then
            (
                echo '<xsl:stylesheet'
                echo ' xmlns:xsl="http://www.w3.org/1999/XSL/Transform"'
                echo ' xmlns:db="http://docbook.org/ns/docbook"'
                echo ' exclude-result-prefixes="db"'
                echo ' version="1.0">'
                echo '<xsl:output method="text"/>'
                echo '<xsl:template match="/">'
                echo ' <xsl:for-each select="'
                echo '   //audiodata | //imagedata | //videodata |'
                echo '   //db:audiodata | //db:imagedata | //db:videodata">'
                echo '  <xsl:value-of select="concat(@fileref, '"'&#x000A;'"')"/>'
                echo ' </xsl:for-each>'
                echo '</xsl:template>'
                echo '</xsl:stylesheet>'
            ) | xsltproc --xinclude - "$xml" | while read media; do
                mfile=`echo "$media" | urldecode`
                minput="$xmldir/$mfile"
                moutput="$html_out/$mfile"
                mkdir_p `dirname "$moutput"`
                cp "$minput" "$moutput"
            done
        fi
        # Copy icons
        (
            echo '<xsl:stylesheet'
            echo ' xmlns:xsl="http://www.w3.org/1999/XSL/Transform"'
            echo ' xmlns:db="http://docbook.org/ns/docbook"'
            echo ' exclude-result-prefixes="db"'
            echo ' version="1.0">'
            echo '<xsl:output method="text"/>'
            echo '<xsl:template match="/">'
            echo ' <xsl:for-each select="(//caution|//warning|//db:caution|//db:warning)[1]">'
            echo '  <xsl:text>yelp-note-warning&#x000A;</xsl:text>'
            echo ' </xsl:for-each>'
            echo ' <xsl:for-each select="(//important|//db:important)[1]">'
            echo '  <xsl:text>yelp-note-important&#x000A;</xsl:text>'
            echo ' </xsl:for-each>'
            echo ' <xsl:for-each select="(//tip|//db:tip)[1]">'
            echo '  <xsl:text>yelp-note-tip&#x000A;</xsl:text>'
            echo ' </xsl:for-each>'
            echo ' <xsl:for-each select="(//note|//db:note)[@role='"'bug'"'][1]">'
            echo '  <xsl:text>yelp-note-bug&#x000A;</xsl:text>'
            echo ' </xsl:for-each>'
            echo ' <xsl:for-each select="(//note|//db:note)[not(@role) or @role!='"'bug'"'][1]">'
            echo '  <xsl:text>yelp-note&#x000A;</xsl:text>'
            echo ' </xsl:for-each>'
            echo '</xsl:template>'
            echo '</xsl:stylesheet>'
        ) | xsltproc --xinclude - "$xml" | sort | uniq | while read icon; do
            cp "${yelp_icon_dir}/${icon}.png" "$html_out/$html_internal_datadir"
        done;
        # Copy jQuery
        cp "${yelp_js_dir}/jquery.js" "$html_out/$html_internal_datadir"
        cp "${yelp_js_dir}/jquery.syntax.js" "$html_out/$html_internal_datadir"
        cp "${yelp_js_dir}/jquery.syntax.core.js" "$html_out/$html_internal_datadir"
        cp "${yelp_js_dir}/jquery.syntax.layout.yelp.js" "$html_out/$html_internal_datadir"
        (
            echo '<xsl:stylesheet'
            echo ' xmlns:xsl="http://www.w3.org/1999/XSL/Transform"'
            echo ' xmlns:db="http://docbook.org/ns/docbook"'
            echo ' xmlns:html="http://www.w3.org/1999/xhtml"'
            echo ' xmlns:exsl="http://exslt.org/common"'
            echo ' exclude-result-prefixes="db"'
            echo ' extension-element-prefixes="exsl"'
            echo ' version="1.0">'
            xsl='file://'`echo "$xsl_db2xhtml" | urlencode`
            echo '<xsl:import href="'"$xsl"'"/>'
            echo '<xsl:output method="text"/>'
            echo '<xsl:template match="/">'
            echo ' <xsl:for-each select="//programlisting[@language] | //db:programlisting[@language]">'
            echo '  <xsl:variable name="out">'
            echo '   <xsl:call-template name="db2html.pre"/>'
            echo '  </xsl:variable>'
            echo '  <xsl:value-of select="exsl:node-set($out)/*/html:pre[last()]/@class"/>'
            echo '  <xsl:text>&#x000A;</xsl:text>'
            echo ' </xsl:for-each>'
            echo '</xsl:template>'
            echo '</xsl:stylesheet>'
        ) | xsltproc --xinclude - "$xml" | sort | uniq \
            | grep '^contents syntax ' | sed -e 's/^contents syntax brush-/brush./' \
            | while read js; do
            cp "${yelp_js_dir}/jquery.syntax.${js}.js" "$html_out/$html_internal_datadir"
        done
    done
}

yelp_html_mal2html () {
    if [ "x$html_cache_file" != "x" ]; then
        html_cache_file=`(cd $(dirname "$html_cache_file") && pwd)`/`basename "$html_cache_file"`
    else
        html_cache_file_is_tmp="yes"
        html_cache_file=`mktemp`
        yelp_cache -o "$html_cache_file" "$@"
    fi
    html_tmp_infile=`mktemp`
    yelp_cache_in "$@" > "$html_tmp_infile"
    (
        echo '<xsl:stylesheet'
        echo ' xmlns:xsl="http://www.w3.org/1999/XSL/Transform"'
        echo ' xmlns:mal="http://projectmallard.org/1.0/"'
        echo ' xmlns:cache="http://projectmallard.org/cache/1.0/"'
        echo ' xmlns:exsl="http://exslt.org/common"'
        echo ' xmlns="http://www.w3.org/1999/xhtml"'
        echo ' exclude-result-prefixes="mal cache"'
        echo ' extension-element-prefixes="exsl"'
        echo ' version="1.0">'
        if [ "x$is_xhtml" = "x1" ]; then
            xsl='file://'`echo "$xsl_mal2xhtml" | urlencode`
        else
            xsl='file://'`echo "$xsl_mal2html" | urlencode`
        fi
        echo '<xsl:import href="'"$xsl"'"/>'
        yelp_html_xsl_common
        html_cache_url='file://'`echo "$html_cache_file" | urlencode`
        echo '<xsl:param name="mal.cache.file" select="'"'$html_cache_url'"'"/>'
        echo '<xsl:template match="/">'
        echo '<xsl:for-each select="cache:cache/mal:page">'
        echo '<xsl:call-template name="html.output">'
        echo '<xsl:with-param name="node" select="document(@cache:href)/mal:page"/>'
        echo '</xsl:call-template>'
        echo '</xsl:for-each>'
        echo '</xsl:template>'
        echo '</xsl:stylesheet>'
    ) | xsltproc $html_profile --xinclude -o "$html_out"/ - "$html_tmp_infile"
    (
        echo '<xsl:stylesheet'
        echo ' xmlns:xsl="http://www.w3.org/1999/XSL/Transform"'
        echo ' xmlns:mal="http://projectmallard.org/1.0/"'
        echo ' xmlns:cache="http://projectmallard.org/cache/1.0/"'
        echo ' xmlns:e="http://projectmallard.org/experimental/"'
        echo ' xmlns:exsl="http://exslt.org/common"'
        echo ' xmlns:html="http://www.w3.org/1999/xhtml"'
        echo ' extension-element-prefixes="exsl"'
        echo ' version="1.0">'
        xsl='file://'`echo "$xsl_mal2xhtml" | urlencode`
        echo '<xsl:import href="'"$xsl"'"/>'
        echo '<xsl:output method="text"/>'
        echo '<xsl:template name="dirname">'
        echo ' <xsl:param name="str"/>'
        echo ' <xsl:if test="contains($str, '\''/'\'')">'
        echo '  <xsl:value-of select="substring-before($str, '\''/'\'')"/>'
        echo '  <xsl:text>/</xsl:text>'
        echo '  <xsl:call-template name="dirname">'
        echo '   <xsl:with-param name="str" select="substring-after($str, '\''/'\'')"/>'
        echo '  </xsl:call-template>'
        echo ' </xsl:if>'
        echo '</xsl:template>'
        echo '<xsl:template match="/">'
        echo '<xsl:for-each select="cache:cache/mal:page">'
	echo ' <xsl:variable name="dir">'
        echo '  <xsl:call-template name="dirname">'
        echo '   <xsl:with-param name="str" select="substring-after(@cache:href, '\''file://'\'')"/>'
        echo '  </xsl:call-template>'
        echo ' </xsl:variable>'
        echo ' <xsl:variable name="node" select="document(@cache:href)/mal:page"/>'
        # Media
        echo ' <xsl:for-each select="$node//mal:media | $node//e:mouseover">'
	echo '  <xsl:if test="not(contains(@src, '\'':'\''))">'
        echo '   <xsl:value-of select="concat($dir, @src, '"' '"')"/>'
        echo '   <xsl:value-of select="concat(@src, '"'&#x000A;'"')"/>'
	echo '  </xsl:if>'
        echo ' </xsl:for-each>'
        # Syntax highlighting
        echo ' <xsl:for-each select="$node//mal:code[@mime]">'
        echo '  <xsl:variable name="out">'
        echo '   <xsl:call-template name="mal2html.pre"/>'
        echo '  </xsl:variable>'
        echo '  <xsl:variable name="class">'
        echo '   <xsl:value-of select="exsl:node-set($out)/*/html:pre[last()]/@class"/>'
        echo '  </xsl:variable>'
        echo '  <xsl:if test="starts-with($class, '\''contents syntax brush-'\'')">'
        echo '   <xsl:text>'"${yelp_js_dir}"'/jquery.syntax.brush.</xsl:text>'
        echo '   <xsl:value-of select="substring-after($class, '\''contents syntax brush-'\'')"/>'
        echo '   <xsl:text>.js ./&#x000A;</xsl:text>'
        echo '  </xsl:if>'
        echo ' </xsl:for-each>'
        # Icons
        echo ' <xsl:for-each select="$node//mal:note">'
        echo '  <xsl:variable name="style" select="concat('\'' '\'', @style, '\'' '\'')"/>'
        echo '  <xsl:choose>'
        echo '   <xsl:when test="contains($style, '\'' advanced '\'')">'
        echo '    <xsl:text>'"${yelp_icon_dir}"'/yelp-note-advanced.png ./&#x000A;</xsl:text>'
        echo '   </xsl:when>'
        echo '   <xsl:when test="contains($style, '\'' bug '\'')">'
        echo '    <xsl:text>'"${yelp_icon_dir}"'/yelp-note-bug.png ./&#x000A;</xsl:text>'
        echo '   </xsl:when>'
        echo '   <xsl:when test="contains($style, '\'' important '\'')">'
        echo '    <xsl:text>'"${yelp_icon_dir}"'/yelp-note-important.png ./&#x000A;</xsl:text>'
        echo '   </xsl:when>'
        echo '   <xsl:when test="contains($style, '\'' sidebar '\'')"/>'
        echo '   <xsl:when test="contains($style, '\'' tip '\'')">'
        echo '    <xsl:text>'"${yelp_icon_dir}"'/yelp-note-tip.png ./&#x000A;</xsl:text>'
        echo '   </xsl:when>'
        echo '   <xsl:when test="contains($style, '\'' warning '\'')">'
        echo '    <xsl:text>'"${yelp_icon_dir}"'/yelp-note-warning.png ./&#x000A;</xsl:text>'
        echo '   </xsl:when>'
        echo '   <xsl:otherwise>'
        echo '    <xsl:text>'"${yelp_icon_dir}"'/yelp-note.png ./&#x000A;</xsl:text>'
        echo '   </xsl:otherwise>'
        echo '  </xsl:choose>'
        echo ' </xsl:for-each>'
        echo '</xsl:for-each>'
        echo '</xsl:template>'
        echo '</xsl:stylesheet>'
    ) | xsltproc --xinclude - "$html_tmp_infile" | sort | uniq |
    while read line; do
	line_src=`echo "$line" | cut -d' ' -f1`
        line_src=`echo "$line_src" | urldecode`
	line_dest="$html_out/$html_internal_datadir"`echo "$line" | cut -d' ' -f2`
        line_dest=`echo "$line_dest" | urldecode`
	if [ "$line_src" != "$line_dest" ]; then
            line_dir=`dirname "$line_dest"`
            mkdir_p "$line_dir"
	    cp "$line_src" "$line_dest"
	fi
    done
    cp "${yelp_js_dir}/jquery.js" "$html_out/$html_internal_datadir"
    cp "${yelp_js_dir}/jquery.syntax.js" "$html_out/$html_internal_datadir"
    cp "${yelp_js_dir}/jquery.syntax.core.js" "$html_out/$html_internal_datadir"
    cp "${yelp_js_dir}/jquery.syntax.layout.yelp.js" "$html_out/$html_internal_datadir"

    rm "$html_tmp_infile"
    if [ "x$html_cache_file_is_tmp" = "xyes" ]; then
        rm "$html_cache_file"
    fi
}

yelp_html () {
    while [ "$#" != "0" ]; do
        case "$1" in
            "-c")
                shift
                html_cache_file="$1"
                shift
                ;;
            "-o")
                shift
                html_out="$1"
                shift
                ;;
            "-x")
                shift
                html_custom="$1"
                shift
                ;;
            "--profile")
                html_profile="--profile"
                shift
                ;;
            *)
                break
                ;;
        esac
    done
    if [ "x$html_out" = "x" ]; then
        html_out="."
    elif [ ! -d "$html_out" ]; then
        echo "Error: output must be a directory." 1>&2
        exit 1
    fi
    html_out=`(cd "$html_out" && pwd)`
    if [ "x$html_custom" != "x" ]; then
        html_custom_dir=`dirname "$html_custom"`
        html_custom_dir=`(cd "$html_custom_dir" && pwd)`
        html_custom="$html_custom_dir"/`basename "$html_custom"`
    fi
    if [ "$#" = "0" -o "x$1" = "x--help" ]; then
        yelp_usage_html
        exit 1
    fi
    ext=`echo "$1" | sed -e 's/.*\.//'`
    if [ "x$ext" = "xxml" -o "x$ext" = "xdocbook" ]; then
        yelp_html_db2html "$@"
    else
        yelp_html_mal2html "$@"
    fi
}

yelp_epub () {
    while [ "$#" != "0" ]; do
        case "$1" in
            "-c")
                shift
                epub_cache_file="$1"
                shift
                ;;
            "-o")
                shift
                epub_out="$1"
                shift
                ;;
            "-x")
                shift
                html_custom="$1"
                shift
                ;;
            *)
                break
                ;;
        esac
    done
    if [ "x$epub_cache_file" != "x" ]; then
        epub_cache_file=`(cd $(dirname "$epub_cache_file") && pwd)`/`basename "$epub_cache_file"`
    else
        epub_cache_file_is_tmp="yes"
        epub_cache_file=`mktemp`
        yelp_cache -o "$epub_cache_file" "$@"
    fi
    html_cache_file="$epub_cache_file"
    epub_data_out=`mktemp -d`
    html_out="$epub_data_out/OPS"
    mkdir "$html_out"
    mkdir "$html_out/yelp"
    html_internal_datadir="yelp/"
    html_internal_xsl="$xsl_mal_epub"
    yelp_html_mal2html "$@"

    epub_id=`uuidgen`
    epub_data=`(cd "$html_out" && ls yelp/*.*)`
    xsltproc \
        -o "$html_out/opf.opf" \
        --stringparam opf.id "$epub_id" \
        --stringparam opf.data "$epub_data" \
        "$xsl_mal_opf" "$epub_cache_file"
    xsltproc \
        -o "$html_out/ncx.ncx" \
        --stringparam ncx.id "$epub_id" \
        "$xsl_mal_ncx" "$epub_cache_file"

    echo "application/epub+zip" > "$epub_data_out/mimetype"

    mkdir "$epub_data_out/META-INF"
    (
        echo "<?xml version='1.0' encoding='UTF-8'?>"
        echo "<container version='1.0' xmlns='urn:oasis:names:tc:opendocument:xmlns:container'>"
        echo "<rootfiles>"
        echo "<rootfile full-path='OPS/opf.opf' media-type='application/oebps-package+xml'/>"
        echo "</rootfiles>"
        echo "</container>"
    ) > "$epub_data_out/META-INF/container.xml"

    if [ "x$epub_out" = "x" ]; then
        epub_out=`pwd`/index.epub
    else
        epub_out=`(cd $(dirname "$epub_out") && pwd)`/`basename "$epub_out"`
    fi
    (cd "$epub_data_out" && zip -q -r "$epub_out" mimetype META-INF OPS)

    if [ "x$epub_cache_file_is_tmp" = "xyes" ]; then
        rm "$epub_cache_file"
    fi
    rm -rf "$html_out"
}

cmd="$1"
shift
case "x$cmd" in
    "xcache")
        yelp_cache "$@"
        ;;
    "xepub")
        is_xhtml=1
        yelp_epub "$@"
        ;;
    "xhtml")
        is_xhtml=0
        yelp_html "$@"
        ;;
    "xxhtml")
        is_xhtml=1
        yelp_html "$@"
        ;;
    *)
        yelp_usage
        ;;
esac
