#!/bin/bash
# -*- coding:utf-8 -*-
# file KLEIDER/web/src/sitestyle/updweb
# 2011-07-09 Herbert Schiemann <h.schiemann@herbaer.de>
# Präsentation der "Bildergeschichten" im Web vorbereiten / aktualisieren

# 2012-07-18 an geänderte Verzeichnisse angepasst
# 2013-06-13 --hlpmont Vorschau-Bildmontagen zur Hilfe
# 2013-08-08 Pfad der Stil-Quelldateien angepasst
# 2014-03-15 Hilfe-Dateien *_help.xhtml im style-Verzeichnis
# 2014-08-28 mobile.xslt, --htaccess, keeptmp
# 2014-09-01 Dateien component/*.dbk
# 2014-09-08 ixmobile.xslt
# 2014-09-26 Dateien *.stub
# 2014-10-15 PRESENTATION_help.xhtml.LANG, PRESENTATION_help.xslt
# 2014-12-02 Anpassungen wg. mod_negotiation für gzip-Komprimierung
# 2014-12-21 --local
# 2015-01-13 --complang
# 2015-07-12 Korrektur process_index: $webdir/
# 2015-07-14 *_help.xslt umbenannt in *_mkhlp.xslt, *_help.xslt "live"
# 2015-12-22 index_treeinc.xslt
# 2015-12-29 proc_compmediadir und proc_compmediafile
# 2016-02-06 dirpath_base, ht_abs2rel.xslt
# 2016-03-28 upload (proc_comp), srcbase
# 2016-07-31 proc_comp: Präfix /l/ nicht ersetzen
# 2017-12-31 --localize
# 2020-04-06 Pfad-Voreinstellungen, show_help überarbeitet
# 2020-05-03 webbase
# 2020-05-15 Lesetexte faltbar: compfoldth, fold.js. fold.css
# 2020-05-23 Bugfix: proc_compmediafile
# 2020-10-02 Zielpfad in htaccess-Dateien,

# Zähler, Variable, Aktionen
declare_vars ()
{
   # Ein Leerzeichen als Wert bedeutet, dass Positionsargumente verarbeitet werden
   _argv="";

   # Suchpfad für rc-Dateien, : - getrennte Liste von Verzeichnispfaden
   # Falls leer, wird die Option --rc nicht speziell behandelt
   g_configpath=$HOME/etc/kleider_herbaer_de/sitestyle_conf.d ;

   # Zähler
   g_counters="  \
      verbose    \
      overwrite  \
      keeptmp    \
      replcompix \
      upload     \
      localize   \
      websrv     ";

   # Variable
   g_variables="    \
      webbase       \
      srcbase       \
      src           \
      webdir        \
      ixsrc         \
      compdir       \
      complang      \
      compimgsz     \
      compfldth     \
      xsltpool      \
      story         \
      tempdir       \
      audio_maxkbps " ;
   # Aktionen
   g_actions="  \
      mkhelp    \
      hlpmont   \
      comp      \
      index     \
      xslt      \
      local     \
      js        \
      css       \
      htaccess  \
      audio     \
      images    " ;
  has_actions=0 ;
} # declare_vars

# Default-Werte setzen
set_defaults () {
   local b=$(realpath $0);
   b=${b%/web/src/sitestyle/updweb};
   [[ -n $verbose       ]] || verbose=1;
   [[ -n $overwrite     ]] || overwrite=0;
   [[ -n $replcompix    ]] || replcompix=1;
   [[ -n $upload        ]] || upload=1;
   [[ -n $localize      ]] || localize=1;
   [[ -n $websrv        ]] || websrv=0;
   [[ -n $webbase       ]] || webbase=$b/web ;
   [[ -n $srcbase       ]] || srcbase=$webbase/src ;
   [[ -n $src           ]] || src=$srcbase/sitestyle ;
   [[ -n $webdir        ]] || webdir=$webbase/docroot ;
   [[ -n $ixsrc         ]] || ixsrc=$webbase/supplement/index.dbk ;
   [[ -n $compdir       ]] || compdir=$webbase/components ;
   [[ -n $complang      ]] || complang=de ;
   [[ -n $compimgsz     ]] || compimgsz=400x400 ;
   [[ -n $compfldth     ]] || compfldth=4 ;
   [[ -n $xsltpool      ]] || xsltpool=$b/pool ;
   [[ -n $story         ]] || story=2015w16 ;
   [[ -n $tempdir       ]] || tempdir=$webbase/temp ;
   [[ -n $audio_maxkbps ]] || audio_maxkbps=60 ;
} # set_defaults

# Variable und Zähler initialisieren
init_vars () {
   local v;
   declare_vars ;
   for v in $g_counters $g_variables $g_actions; do
      eval "$v=" ;
   done;
} # init_vars

# Ist der Dateipfad sicher, d.h
# - Hat nur der Besitzer mehr als nur Leserecht für die Datei?
# - Hat nur der Besitzer Schreibrecht für das Verzeichnis?
# - Ist der Besitzer der Datei auch der Besitzer des Verzeichnisses?
# - Ist die Datei nicht im Wurzelverzeichnis?
is_secure ()
{
   local chk ;
   (( verbose )) && echo "prüfe Sicherheit $1" ;
   [[ -f "$1" && -r "$1" ]] || return 1 ;
   chk=$(stat --format=%A "$1") ;
   [[ $chk =~ ^.{4}[r-]{6}$ ]] || return 1 ;
   chk=${1%/*};
   [[ -n "$chk" ]] || return 1;
   [[ "$chk" != "$1" ]] || chk=$(pwd);
   [[ -d "$chk" ]] || return 1 ;
   [[ $(stat --format=%u "$chk") == $(stat --format=%u "$1") ]] || return 1;
   chk=$(stat --format=%A "$chk") ;
   if [[ $chk =~ ^.{4}[rx-]{6}$ ]]; then
      (( verbose )) && echo "Datei $1 scheint sicher";
      return 0;
   fi;
   return 1;
}

# read_configuration file
# file: Dateiname ("rc"-Datei) ohne Endung ".rc"
read_configuration ()
{
   local path=$g_configpath ;
   local file=$1.rc ;
   local dir;
   while [[ -n "$path" ]]; do
      dir=${path%%:*} ;
      if is_secure "$dir/$file"; then
         source "$dir/$file";
         return 0;
      fi;
      path=${path#*:} ;
      [[ "$dir" == "$path" ]] && break;
   done;
   return 1;
} # read_configuration

# Liste der existierenden Konfigurationen
list_configurations ()
{
   local path=$g_configpath ;
   local cfg=" ";
   local dir;
   local f;
   while [[ -n "$path" ]]; do
      dir=${path%%:*} ;
      for f in $dir/*.rc; do
         [[ -f $f && -r $f && -s $f ]] || continue ;
         f=${f##*/};
         f=${f%.rc};
         [[ -n $f ]] || continue ;
         [[ "$cfg" == "${cfg#* $f }" ]] && cfg="$cfg $f " ;
      done ;
      path=${path#*:} ;
      [[ "$dir" == "$path" ]] && break;
   done;
   cfg=${cfg# };
   echo ${cfg% };
}

# Argumente verarbeiten
read_args ()
{
   local wd ;
   local lastwd ;
   local var ;
   local ok ;

   has_actions=0 ;
   for wd in "$@"; do
      if [[ "$lastwd" = "--" ]]; then
          _argv="$_argv $wd";
      elif [[ -n "$lastwd" ]]; then
         if [[ "$wd" =~ ^[\ a-zA-Z0-9./_#-]+$ ]]; then
            if [[ "$lastwd" == "rc" && -n "$g_configpath" ]]; then
               if ! read_configuration $wd; then
                  (( verbose )) && echo "Kann Konfiguration $wd nicht lesen" ;
                  exit 10 ;
               fi ;
            else
               ok=0 ;
               for var in $g_variables; do
                  if [[ "$var" == "$lastwd" ]]; then
                     (( ++ok )) ;
                     eval "$var=\"$wd\"" ;
                     break ;
                  fi ;
               done ;
               if (( ! ok )); then
                  (( verbose )) && echo "Unbekannte Option --$lastwd $wd" ;
                  exit 11 ;
               fi ;
            fi ;
         else
            (( verbose )) && echo "Ungültiger Optionswert --$lastwd $wd" ;
            exit 12;
         fi;
         lastwd= ;
      else
         case "$wd" in
            --version )
               show_version ;
               exit 0 ;
               ;;
            --help )
               show_version ;
               show_help ;
               exit 0 ;
               ;;
            -- )
               if [[ -n "$_argv" ]]; then
                  lastwd=--;
                  continue;
               else
                  (( verbose )) && echo "Ungültige Option $wd" ;
                  exit 13 ;
               fi ;
               ;;
            --* )
               if [[ "$wd" =~ ^--[a-z][a-z0-9_]*$ ]]; then
                  lastwd=${wd#--} ;
                  ok=0 ;
                  for var in $g_counters ; do
                     if   [[ "$lastwd" == $var    ]]; then
                        eval "(( ++$lastwd ))" ;
                     elif [[ "$lastwd" == "no_$var" ]]; then
                        eval "${lastwd#no_}=0" ;
                     else
                        continue;
                     fi;
                     (( ++ok )) ;
                     break ;
                  done;
                  if (( !ok )); then
                     for var in $g_actions; do
                        if [[ "$lastwd" == "$var" ]]; then
                           eval "(( ++$var ))" ;
                           (( ++ok ));
                           has_actions=1;
                           break;
                        elif [[ "$lastwd" == "no_$var" ]]; then
                           eval "(( ++no_$var ))" ;
                           (( ++ok ));
                           break;
                        fi;
                     done;
                  fi;
                  (( ok )) && lastwd=;
               else
                  (( verbose )) && echo "Ungültige Option $wd" ;
                  exit 14 ;
               fi ;
               ;;
            * )
               if [[ -n $_argv ]]; then
                   _argv="$_argv $wd";
               else
                   (( verbose )) && echo "Ungültige Option $wd" ;
                   exit 15 ;
               fi;
               ;;
         esac ;
      fi ;
   done ;
   if [[ -n $lastwd && "$lastwd" != "--" ]]; then
      (( verbose )) && echo "Unverarbeitete Option --$lastwd";
      exit 16 ;
   fi ;
} # read_args

# Aktionen ausführen
run_actions ()
{
   local act ;
   for act in $g_actions; do
     eval "(( ! has_actions && ! no_$act || $act )) && process_$act";
   done;
} # run_actions

# Werte der Variablen anzeigen
show_variables ()
{
   local v ;
   for v in $g_counters $g_variables $g_actions $1; do
      eval "echo \"$v = \$$v\"" ;
   done;
} # show_variables

# Zeigt eine kurze Hilfe an
show_help ()
{
   local cmd=${0#*/} ;
   set_defaults ;
   cat << .HELP ;
$cmd --version
$cmd --help
$cmd [Option]*
--rc RC                Einstellungen aus $g_configpath/RC.rc lesen
                       ($(list_configurations))
--[no_]verbose         Ablauf nach stdout ausgeben ($verbose)?
--[no_]overwrite       Existierende Dateien überschreiben ($overwrite)?
--webbase  WEBBASE     Web-Basisverzeichnis ($webbase)
--srcbase  SRCBASE     übergeordnetes Quell-Verzeichnis ($srcbase)
--src      SRC         Quell-Verzeichnis ($src)
--webdir   WEBDIR      Web-Verzeichnis ($webdir)
--xsltpool XSLTPOOL    Verzeichnis der gemeinsamen XSLT-Dateien ($xsltpool)
--tempdir  TEMPDIR     Verzeichnis für temporäre Dateien ($tempdir)
--[no_]keeptmp         Temporäre Dateien behalten ($keeptmp)?
--mkhelp               Hilfe-Dateien erzeugen
--story STORY          Kennung der Bildergeschichte für Bilder der Hilfe ($story)
--hlpmont              Bildmontagen zur Hilfe
--index                Index-XHTML-Datei (Startseite) erzeugen
--ixsrc IXSRC          Quelltext der Startseite ($ixsrc)
--xslt                 XSLT-Dateien
--local                Lokalisierungs-Dateien
--js                   Javascript-Dateien
--css                  CSS-Dateien
--htaccess             Datei style/.htaccess
--[no_]websrv          Werte für den Webserver statt den lokalen Server ($websrv)
--audio                ogg-vorbis - Audio-Dateien
--audio_maxkbps KBPS   Maximale Bitrate (kb/s) für Audio-Dateien ($audio_maxkbps)
--images               Bilddateien (Stil)
--comp                 Komponenten im XHTML-Format
--compdir    COMPDIR   Quellverzeichnis der Lese-Beiträge ($compdir)
--complang   COMPLANG  Default-Sprache der Lese-Beiträge ($complang)
--compimgsz  WxH       Bildgröße im Komponentenverzeichnis ($compimgsz)
--compfldth  COMPFLDTH Faltung ab COMPFLDTH Abschnitten in einem Lese-Beitrag ($compfldth)
--[no_]replcompix      Existierende Komponenten-Indexdatei ersetzen ($replcompix)?
--[no_]upload          Lesebeiträge/Komponenten hochladen? ($upload)
--[no_]localize        Komponenten vor dem Hochladen übersetzen ($localize)?
.HELP
} # show_help

# Zeigt die Version an
show_version ()
{
   cat << .VERSION ;
updweb 20200515
Website kleider.herbaer.de: Startseite, Komponenten, Stil aktualisieren
2020-05-15, Herbert Schiemann, h.schiemann@herbaer.de
GPL Version 2 oder neuer
.VERSION
} # show_version

# Kann die Ausgabedatei erstellt werden?
check_outfile ()
{
   local fp=$1;
   local dir;
   local verb;
   (( verbose )) && verb=--verbose ;
   if [[ ! -e $fp ]]; then
      dir=${fp%/*};
      if [[ -n $dir && ! -e $dir ]]; then
         mkdir -p $verb $dir ;
         if [[ ! -d $dir ]]; then
            (( verbose )) && echo "$dir ist kein Verzeichnis";
            return 1;
         fi;
      fi;
   fi;

   if [[ -d $fp ]]; then
      (( verbose )) && echo "$fp ist ein Verzeichnis";
      return 1;
   elif [[ -d $fp. ]]; then
      (( verbose )) && echo "$fp. ist ein Verzeichnis";
      return 1;
   elif (( overwrite )); then
      if [[ -e $fp ]]; then
         (( verbose )) && echo "lösche $fp";
         rm $fp;
      fi;
      if [[ -e $fp. ]]; then
         (( verbose )) && echo "lösche $fp.";
         rm $fp.;
      fi;
   else
      if [[ -e $fp ]]; then
         (( verbose )) && echo "$fp existiert";
         return 1;
      fi;
      if [[ -e $fp. ]]; then
         (( verbose )) && echo "$fp. existiert";
         return 1;
      fi;
   fi;
   (( verbose )) && echo "$fp";
   return 0;
} # check_outfile

# Sind Dateien lesbar und nicht leer?
# check_infile file1 file2 ...
check_infile ()
{
   local f ;
   for f in "$@"; do
      if [[ ! -f "$f" ]]; then
         (( verbose )) && echo "Datei $f existiert nicht";
         return 1;
      fi;
      if [[ ! -s "$f" ]]; then
         (( verbose )) && echo "Datei $f ist leer";
         return 1;
      fi;
      if [[ ! -r "$f" ]]; then
         (( verbose )) && echo "Datei $f kann nicht gelesen werden";
         return 1;
      fi;
   done;
   return 0;
} # check_infile

# Sind die Dateien ausführbar?
# check_executeable first/path/to/script path/to/second_srcipt ;
check_executeable ()
{
   local f ;
   for f in "$@"; do
      if [[ ! -f "$f" ]]; then
         (( verbose )) && echo "$f\" ist keine gewöhnliche Datei";
         return 1;
      fi;
      if [[ ! -x "$f" ]]; then
         (( verbose )) && echo "$f\" ist keine ausführbare Datei";
         return 1;
      fi;
   done;
   return 0;
} # check_executeable

# gzip-komprimierte Datei(en) hinzufügen
add_gzip ()
{
   local f;
   for f in "$@"; do
      [[ -f $f ]] || continue;
      [[ -f $f.gz ]] && rm $f.gz;
      [[ -e $f.gz ]] && continue;
      (( verbose )) && echo "erstelle $f.gz";
      gzip --best --stdout $f > $f.gz ;
      (( verbose )) && echo "umbennen $f -> $f.";
      mv $f $f.;
   done ;
} # add_gzip

# Hilfsfunktion: temporäre Javascript und CSS-Dateien erzeugen
# proc_tempfiles subdir
proc_tempfiles ()
{
   local td=$1 ; # Verzeichis der Zwischendateien
   local s;      # Quelldatei
   local o;      # Ausgabedatei
   for s in $src/*.js ; do
      [[ -f $s ]] || continue;
      o=$td/${s#$src/} ;
      check_outfile $o                \
      && $src/clean_js.pl --in $s --out $o ;
   done;
   for s in $src/*.css ; do
      [[ -f $s ]] || continue;
      o=$td/${s#$src/} ;
      check_outfile $o                                                \
      && $src/clean_css.pl --in $s --imageprefix '${imageprefix}' --out $o ;
   done;
} # proc_tempfiles

# Hilfsfunktion: Datei mit kurzen Text-Schlüsseln
# proc_shortids subdir
proc_shortids ()
{
   local sd=$1;
   (( verbose )) && echo "proc_shortids $1";
   local p=$src/shortids.pl ;
   local t=$src/localization_idlist.xslt ;
   local ids=$sd/shortids.xml ;
   local loc=$src/local.xml.de ;
   check_executeable $p || return 1 ;
   check_infile $t $loc || return 1 ;
   check_outfile $ids   || return 1 ;
   xsltproc $t $loc | $p > $ids;
   return 0 ;
} # proc_shortids

# Hilfe-Dateien erzeugen
process_mkhelp ()
{
   local h  ;  # Pfad einer Hilfe-Vorlage (PRESENTATION_help.xhtml.de)
   local b  ;  # Dateiname der Hilfedatei ohne Verzeichnispfad
   local tl ;  # Pfad der speziellen XSLT-Transformation
   local t  ;  # Pfad der XSLT-Datei help_step_1.xslt
   local t2 ;  # Pfad der XSLT-Datei help_step_2.xslt
   local tp ;  # Pfad der XSLT-Datei zur Ersetzung der Platzhalter
   local o  ;  # Pfad der Ausgabedatei
   local l  ;  # Kennung der Sprache
   local p  ;  # Skript zur Entfernung von Namensraumknoten
   (( verbose )) && echo "process_mkhelp" ;
   local td="$tempdir/$(date +%Y%m%d%H%M%S%N)" ;
   proc_tempfiles $td ;
   t=$src/help_step_1.xslt ;
   t2=$src/help_step_2.xslt ;
   tp=$src/localization_repltext.xslt ;
   p=$src/rmxmlns.pl ;
   for h in $src/*_help.xhtml.*; do
      [[ $h =~ ~$ ]] && continue ;
      b=${h#$src/};
      o=$webdir/style/$b;
      check_outfile $o || continue;
      to=$td/$b;
      l=${h##*.} ;
      tl=$src/${b%_help.xhtml.*}_mkhlp.xslt ;
      if check_infile $tl; then
         xsltproc                                                  \
            --stringparam p_local $src/local.xml.$l                \
            $tp $h                                                 \
         | xsltproc                                                \
            --stringparam p_fnstory  $webdir/s$story/story.xml.de. \
            $tl -                                                  \
         | xsltproc $xsltpool/xhtml_minimize.xslt -                \
         | $p > $o
      elif check_infile $tp $t $t2; then
         xsltproc                                        \
            --stringparam p_local $src/local.xml.$l      \
            $tp $h                                       \
         | xsltproc --stringparam p_tmpprefix $td/ $t -  \
         | xsltproc --xinclude $t2 -                     \
         | $p > $o                                       ;
      fi;
      add_gzip $o ;
   done ;
   (( keeptmp )) || rm --recursive $td ;
} # process_mkhelp

# Montierte Vorschau-Leisten zur Hilfe
process_hlpmont ()
{
   (( verbose )) && echo "process_hlpmont" ;
   local h;  # Hilfe-Datei im Server-Verzeichnis
   local t1; # XSLT-Transformation zur Darstellung der Hilfe
   local t2; # XSLT-Transformation zur Erzeugung der Bildmontage
   h=$webdir/style/desktop_help.xhtml.de. ;
   t1=$webdir/style/desktop_help.xslt. ;
   t2=$src/desktop_montage.xslt ;
   check_infile $h $t1 $t2 || return;
   cd $webdir ;
   eval $(xsltproc $t1 $h                        \
      | xsltproc                                 \
      --stringparam p_imgprf s$story/images/     \
      --stringparam p_montdir style/desktop_mont \
      $t2 -);
   cd - ;
} # process_hlpmont

# Hilfsfunktion: Verzeichnispfad-Komponenten durch ".." ersetzten
# dirpath_base auto/bahn/bau/stelle ergibt ../../../..
# dirpath_base ""                   ergibt .
dirpath_base ()
{
   local p=$1;
   local o="";
   if [[ -z $p ]]; then
      o=. ;
   else
      while [[ -n "$p" ]]; do
         if [[ "$p" =~ ^[^/]+/(.+)$ ]]; then
            o=$o../ ;
            p=${BASH_REMATCH[1]} ;
         elif [[ "$p" =~ ^/(.+)$ ]]; then
            o=$o/ ;
            p=${BASH_REMATCH[1]} ;
         else
            o=$o.. ;
            p="" ;
         fi;
      done;
   fi;
   echo $o;
} # dirpath_base

# Hilfsfunktion:
# eine Mediendatei
proc_compmediafile ()
{
   local s=$1;
   local o=$webdir/comp${s#$compdir} ; # Ausgabedatei
   if [[ $s =~ \.jpg$ ]]; then
      check_outfile $o || return;
      convert -resize $compimgsz $s $o;
      echo "put comp${s#$compdir}" >> $comp_UPLOAD ;
   fi;
} # proc_compmediafile

# Hilfsfunktion:
# Mediendateien in einem Unterverzeichnis
proc_compmediadir ()
{
   local sdir=$1;
   local s;    # Quelldatei
   for s in $sdir/*; do
      if [[ -d $s ]]; then
         proc_compmediadir $s;
      else
         proc_compmediafile $s;
      fi
   done;
} # proc_compmediadir

# Hilfsfunktion: Lesebeiträge in einem Unterverzeichnis
proc_comp ()
{
   local sdir=$1 ;
   local ix=$2 ;
   local level=$3 ;
   local nl ;         # anderer Level
   (( verbose )) && echo "Verzeichnis $sdir";
   local t=$src/comp_dbk_ht.xslt;
   local s;   # Quelle
   local o;   # Ausgabedatei ohne Sprachkennung
   local ol;  # Ausgabedatei mit Sprachkennung
   local o2;  # rel. Pfad der Ausgabedatei mit Sprachkennung
   local o2;  # rel. Pfad der Ausgabedatei
   local l;   # Sprachkennung 
   local p=comp${sdir#$compdir} ;
   echo "<dir name=\"$p\">" >> $ix;
   p=$(dirpath_base $p) ; # relativer Pfad zu $webdir (DOCROOT)
   for s in $sdir/* ; do
      nl=$level ;
      if [[ -d $s ]]; then
         if [[ $s =~ \.d$ ]]; then
            proc_compmediadir $s;
         else
            (( ++nl )) ;
            proc_comp $s $ix $nl;
         fi;
      elif [[ $s =~ \.dbk$ ]]; then
         [[ $s =~ /index\.dbk$ ]] || (( ++nl ));
         o=comp${s#$compdir} ;
         o=${o%.dbk}.xhtml ;
         echo "<file>$o</file>" >> $ix ;
         o=$webdir/$o ;
         check_outfile $o || continue ;
         l=$(xsltproc $src/language.xslt $s) ;
         [[ -n $l ]] || l=$complang ;
         ol=$o.$l ;
         check_outfile $ol || continue ;
         xsltproc                                   \
           --stringparam p_level $nl                \
           --stringparam p_foldthreshold $compfldth \
           $t $s                                    \
         | xsltproc $src/xhtml_add_linkthumbs.xslt -        \
         | xsltproc                                         \
           --stringparam p_oprf /l/,/                       \
           --stringparam p_nprf /l/,$p/                     \
           $src/ht_abs2rel.xslt -                           \
         | xsltproc -o $ol $src/xhtml_minimize_index.xslt - ;
         add_gzip $ol ;
         o2=${ol#$webdir/};
         o3=${o#$webdir/};
         [[ -f $ol.   ]] && echo "put $o2."   >> $comp_UPLOAD ;
         [[ -f $ol.gz ]] && echo "put $o2.gz" >> $comp_UPLOAD ;
         [[ -f $ol.   ]] && echo $o3          >> $comp_TRANSLATE ;
      else
         proc_compmediafile $s;
      fi;
   done;
   echo "</dir>" >> $ix;
} # proc_comp

# Komponenten erzeugen
process_comp ()
{
   (( verbose )) && echo "process_comp";
   local t=$src/comp_dbk_ht.xslt
   if [[ ! -f $t ]]; then
      (( verbose )) && echo "Kann Datei $t nicht lesen";
      return;
   fi;
   local td="$tempdir/$(date +%Y%m%d%H%M%S%N)" ;
   comp_TRANSLATE=$td/comp_translate ;
   comp_UPLOAD=$td/comp_upload ;
   check_outfile $comp_TRANSLATE $comp_UPLOAD ;
   local d ;  # Docbook-Datei oder Unterverzeichnis
   local ix ;
   local ow=$overwrite ;
   local ol;  # Ausgabedatei mit Sprachkennung
   local o2;  # rel. Pfad der Ausgabedatei mit Sprachkennung
   local o3;  # rel. Pfad der Ausgabedatei
   local l;   # Sprachkennung
   for d in $compdir/* ; do
      if [[ -d $d ]]; then
         if [[ $s =~ \.d$ ]]; then
            proc_compmediadir $d;
         else
            ix="$d/index.xml" ;
            overwrite=$replcompix ;
            check_outfile $ix || continue;
            overwrite=$ow ;
            echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>" > $ix ;
            echo "<components xmlns=\"http://herbaer.de/xmlns/20121016/components\">" \
               >> $ix ;
            proc_comp $d $ix 2;
            echo "</components>" >> $ix ;
         fi
      elif [[ $d =~ \.dbk$ ]]; then
         o=$webdir/comp${d#$compdir} ;
         o=${o%.dbk}.xhtml ;
         check_outfile $o || continue ;
         l=$(xsltproc $src/language.xslt $d) ;
         [[ -n $l ]] || l=$complang ;
         ol=$o.$l ;
         check_outfile $ol || continue ;
         xsltproc --stringparam p_level 2 $t $d             \
         | xsltproc -o $ol $src/xhtml_minimize_index.xslt - ;
         add_gzip $ol ;
         o2=${ol#$webdir/};
         o3=${o#$webdir/};
         [[ -f $ol.   ]] && echo "put $o2."   >> $comp_UPLOAD ;
         [[ -f $ol.gz ]] && echo "put $o2.gz" >> $comp_UPLOAD ;
         [[ -f $ol.   ]] && echo $o3          >> $comp_TRANSLATE ;
      else
         proc_compmediafile $d;
      fi;
   done;
   overwrite=$ow ;
   if (( upload )); then
      local verb;
      (( verbose )) && verb=--verbose ;
      if (( localize ))                                       \
         && check_infile $comp_TRANSLATE                      \
         && check_executeable $srcbase/localization/localize  ;
      then
         $srcbase/localization/localize --overwrite $verb --srclang $complang \
            $(cat $comp_TRANSLATE)                                            ;
      fi;
      if check_infile $comp_UPLOAD && check_executeable $srcbase/localization/ftp.pl;
      then
         cat $comp_UPLOAD                     \
         | $srcbase/localization/ftp.pl $verb \
            --putbase $webdir                 ;
      fi;
   fi;
   (( keeptmp )) || rm --recursive $td ;
} # process_comp

# Index-XHTML-Datei (Startseite) erzeugen
process_index ()
{
   local out=$webdir/index.xhtml ;
   (( verbose )) && echo "process_index";
   check_outfile $out || return ;
   local l;   # Sprachkennung
   l=$(xsltproc $src/language.xslt $ixsrc) ;
   [[ -n $l ]] || l=$complang ;
   out=$out.$l ;
   check_outfile $out || return ;
   (( verbose )) && echo "$ixsrc -> $out" ;
   xsltproc                                            \
     --stringparam p_incprf   $compdir/                \
     --stringparam p_localprf $webdir/                 \
     $src/index_comp.xslt $ixsrc                       \
   | xsltproc                                          \
      --stringparam p_fileprf $webbase/                \
      $src/index_treeinc.xslt -                        \
   | xsltproc                                          \
      --stringparam p_styleprefix style                \
      $src/index_dbk_ht.xslt -                         \
   | xsltproc -o $out $src/xhtml_minimize_index.xslt - ;
   add_gzip $out ;
} # process_index

# XSLT-Dateien
process_xslt ()
{
   local s ; # Pfad einer XSLT-Datei (Quelle)
   local n ; # Basis-Name ohne Verzeichnispfad oder '.xslt' oder '.stub'
   local a ; # Dateinamenssuffix 'xslt' oder 'stub'
   local o ; # Zielverzeichnis $webdir/style
   local o2; # Zielpfad
   (( verbose )) && echo "process_xslt";

   local td="$tempdir/$(date +%Y%m%d%H%M%S%N)" ;
   proc_tempfiles $td ;
   proc_shortids  $td  || return ;
   o=$webdir/style ;
   [[ -L $o ]] && return ;
   for n in                                  \
      ixdesk ixmobile                        \
      desktop mobile galery imgview kal pinw \
      smdesk smmobile smview                 ;
   do
      for a in .xslt .stub _help.xslt ;
      do
         s=$src/$n$a ;
         [[ -f $s ]] || continue ;
         o2=$o/$n$a ;
         check_outfile $o2 || continue;
         xsltproc                                           \
            --stringparam p_tmpprefix $td/                  \
            --stringparam p_shortids $td/shortids.xml       \
            $src/styleincl_step_1.xslt $s                   \
         | xsltproc --xinclude $src/styleincl_step_2.xslt - \
         > $o2                                              ;
         add_gzip $o2 ;
      done;
   done;
   (( keeptmp )) || rm --recursive $td ;
} # process_xslt

# Lokalisierungen
process_local ()
{
   local f;  # Lokalisierungs-Quelldatei
   local d;  # Lokalisierungs-Zieldatei
   (( verbose )) && echo "process_local";
   local t=$src/localization_shortids.xslt ;
   check_infile $t || return ;
   local td="$tempdir/$(date +%Y%m%d%H%M%S%N)" ;
   proc_shortids  $td || return ;
   for f in $src/local.xml* ; do
      [[ $f =~ ~$ ]] && continue;
      d=$webdir/local/${f#$src/} ;
      check_outfile $d || continue ;
      xsltproc                                      \
        --stringparam p_shortids $td/shortids.xml   \
        $t $f                                       \
      | xsltproc                                    \
        --param p_pi 0                              \
        $xsltpool/xml_minimize.xslt - > $d          ;
      add_gzip $d;
   done;
   (( keeptmp )) || rm --recursive $td ;
} # process_local

# Javascript-Dateien
process_js ()
{
   local b  ; # Basisname einer Javascript-Datei
   local s  ; # Pfad einer Javascript-Datei (Quelle)
   local o  ; # Zielverzeichnis $webdir/style
   local o2 ; # Zielpfad
   (( verbose )) && echo "process_js";
   o=$webdir/style ;
   [[ -L $o ]] && return ;
   for b in common fold; do
      s=$src/$b.js ;
      [[ -f $s ]] || continue ;
      o2=$o/$b.js ;
      check_outfile $o2 || continue ;
      $src/clean_js.pl --in $s --out $o2 ;
      add_gzip $o2 ;
   done;
} # process_js

# CSS-Dateien
process_css ()
{
   local b  ; # Basisname einer CSS-Datei
   local s  ; # Pfad einer CSS-Datei (Quelle)
   local o  ; # Zielverzeichnis $webdir/style
   local o2 ; # Zielpfad
   (( verbose )) && echo "process_css";
   o=$webdir/style ;
   [[ -L $o ]] && return ;
   for b in embedded fold; do
      s=$src/$b.css ;
      [[ -f $s ]] || continue ;
      o2=$o/$b.css ;
      check_outfile $o2 || continue ;
      $src/clean_css.pl --in $s --out $o2 ;
      add_gzip $o2 ;
   done;
} # process_css

# htaccess - Dateien
process_htaccess ()
{
   (( verbose )) && echo "process_htaccess";
   local o;  # Ziel-Datei
   local s=$webbase/secrets;
   local d=$srcbase/pinw/pival.pl ;
   local r=$srcbase/localization/replace.pl;
   local c=$srcbase/sitestyle/clean_config.pl;
   check_executeable $d $r $c || return:
   local t=$tempdir/upload ;
   if ! [[ -f $t ]] && ! check_outfile $t; then
      return;
   fi;
   local f;
   local w= ;
   (( websrv )) && w="--var web";
   for f in $src/*htaccess; do
      o=$($d < $f);
      [[ -n "$o" ]] || continue;
      [[ $o =~ ^/ ]] || o=$webdir/$o;
      check_outfile $o || continue;
      o=$(realpath $o);
      $r --val $s $w < $f | $c > $o;
      if (( websrv )) && [[ $o =~ ^$webdir ]]; then
         echo "put ${o#$webdir/}" >> $t;
      fi;
   done;
} # process_htaccess

# ogg-vorbis Audio-Dateien
process_audio ()
{
   local s  ; # Pfad einer Audio-Datei (Quelle)
   local o  ; # Zielverzeichnis $webdir/style
   local o2 ; # Zielpfad
   (( verbose )) && echo "process_audio";
   o=$webdir/style ;
   [[ -L $o ]] && return ;
   for s in $src/*.wav ; do
      [[ -f $s ]] || continue;
      o2=$o/${s#$src/} ;
      o2=${o2%.wav}.ogg;
      (( verbose )) && echo "$s -> $o2";
      check_outfile $o2                                                                 \
      && oggenc --max-bitrate=$audio_maxkbps --resample 44100 --downmix --output=$o2 $s ;
   done;
   for s in $src/*.ogg ; do
      [[ -f $s ]] || continue;
      o2=$o/${s#$src/} ;
      check_outfile $o2 && cp $s $o2 ;
   done;
} # process_audio

# Bilddateien
process_images ()
{
   local s  ; # Pfad einer Bilddatei
   local o  ; # Zielverzeichnis $webdir/style
   local o2 ; # Zielpfad
   (( verbose )) && echo "process_images";
   o=$webdir/style ;
   [[ -L $o ]] && return ;
   for s in $src/*.png ; do
      [[ -f $s ]] || continue;
      o2=$o/${s#$src/} ;
      check_outfile $o2 && cp $s $o2 ;
   done;
} # process_images

# Sicherheit
# export PATH=/bin:/usr/local/bin:/usr/bin ;
IFS=$' \t\n' ;
set -o noclobber ;   # existierende Dateien werden nicht überschrieben
shopt -s extglob nullglob ;

# Sicherheit noch einmal nach dem "source"
# export PATH=/bin:/usr/local/bin:/usr/bin ;
IFS=$' \t\n' ;
set -o noclobber ;   # existierende Dateien werden nicht überschrieben
shopt -s extglob nullglob ;
init_vars ;
read_args "$@" ;
set_defaults ;

(( verbose > 1 )) && show_variables ;
run_actions ;
exit 0;
# end of file KLEIDER/web/src/sitestyle/updweb
