diff --git a/vendor/ini.class.sh b/vendor/ini.class.sh
index 9fd7606ad645c5990c17afd7d2e92ee2d3eae0b8..3b1dbf8409abe340eaf299b06ad2ac990af3cc13 100644
--- a/vendor/ini.class.sh
+++ b/vendor/ini.class.sh
@@ -16,6 +16,8 @@
 # 2024-02-12  v0.4  rename local varables
 # 2024-02-20  v0.5  handle special chars in keys; add ini.dump + ini.help
 # 2024-02-21  v0.6  harden ini.value for keys with special chars; fix fetching last value
+# 2024-03-17  v0.7  add ini.validate
+# 2024-03-17  v0.8  errors are written to STDERR; update help; use [[:space:]] in regex; update help
 # ======================================================================
 
 INI_FILE=
@@ -32,7 +34,7 @@ function ini.set(){
     INI_FILE=
     INI_SECTION=
     if [ ! -f "$1" ]; then
-        echo "ERROR: file does not exist: $1"
+        echo "ERROR: file does not exist: $1" >&2
         exit 1
     fi
     INI_FILE="$1"
@@ -45,14 +47,14 @@ function ini.set(){
 # param  string  section
 function ini.setsection(){
     if [ -z "$INI_FILE" ]; then
-        echo "ERROR: ini file needs to be set first. Use ini.set <FILE> [<SECTION>]."
+        echo "ERROR: ini file needs to be set first. Use ini.set <INIFILE> [<SECTION>]." >&2
         exit 1
     fi
     if [ -n "$1" ]; then
         if ini.sections "$INI_FILE" | grep "^${1}$" >/dev/null; then
             INI_SECTION=$1
         else
-            echo "ERROR: Section [$1] does not exist in [$INI_FILE]."
+            echo "ERROR: Section [$1] does not exist in [$INI_FILE]." >&2
             exit 1
         fi
     fi
@@ -75,7 +77,7 @@ function ini.sections(){
 function ini.section(){
         local myinifile=${1:-$INI_FILE}
         local myinisection=${2:-$INI_SECTION}
-        sed -e "0,/^\[${myinisection}\]/ d" -e '/^\[/,$ d' $myinifile \
+        sed -e "0,/^\[${myinisection}\]/ d" -e '/^\[/,$ d' "$myinifile" \
             | grep -v "^[#;]" \
             | sed -e "s/^[ \t]*//g" -e "s/[ \t]*=[ \t]*/=/g"
 }
@@ -110,12 +112,11 @@ function ini.value(){
             local out
             regex="${myvarname//[^a-zA-Z0-9:()]/.}"
             out=$(ini.section "${myinifile}" "${myinisection}" \
-                | sed "s,^[\ \t]*,,g" \
-                | sed "s,[\ \t]*=,=,g"  \
+                | sed -e "s,^[[:space:]]*,,g" -e "s,[[:space:]]*=,=,g"  \
                 | grep -F "${myvarname}=" \
                 | grep "^${regex}=" \
                 | cut -f 2- -d "=" \
-                | sed -e 's,^\ *,,' -e 's, *$,,' 
+                | sed -e 's,^[[:space:]]*,,' -e 's,[[:space:]]*$,,' 
                 )
             grep "\[\]$" <<< "$myvarname" >/dev/null || out="$( echo "$out" | tail -1 )"
 
@@ -137,26 +138,38 @@ ini.dump() {
     echo "|"
     echo -e "+----------------------------------------\e[0m"
     echo -e "\e[34m"
-    cat "$myinifile" | sed "s,^,    ,g"
+    sed "s,^,    ,g" "${myinifile}"
     echo -e "\e[0m"
 
     echo "    Parsed data:"
     echo
     ini.sections "$myinifile" | while read -r myinisection; do
-        echo -e "    --+-- section \e[35m[$myinisection]\e[0m"
-        echo "      |"
-        ini.keys "$myinifile" "$myinisection" | while read -r mykey; do
-            value="$(ini.value "$myinifile" "$myinisection" "$mykey")"
-            # printf "        %-15s => %s\n" "$mykey" "$value"
-            printf "      \`---- %-20s => " "$mykey"
-            echo -e "\e[1;36m$value\e[0m"
-        done
+        if ! ini.keys "$myinifile" "$myinisection" | grep -q "."; then
+            echo -e "    ----- section \e[35m[$myinisection]\e[0m"
+        else
+            echo -e "    --+-- section \e[35m[$myinisection]\e[0m"
+            echo    "      |"
+            ini.keys "$myinifile" "$myinisection" | while read -r mykey; do
+                value="$(ini.value "$myinifile" "$myinisection" "$mykey")"
+                # printf "        %-15s => %s\n" "$mykey" "$value"
+                printf "      \`---- %-20s => " "$mykey"
+                echo -e "\e[1;36m$value\e[0m"
+            done
+        fi
         echo
     done
     echo
 }
 
 function ini.help(){
+
+    # local _self
+    # if _is_sourced; then
+    #     _self="ini."
+    # else
+    #     _self="$( basename "$0" ) "
+    # fi
+
     cat <<EOH
 
     INI.CLASS.SH
@@ -180,16 +193,16 @@ function ini.help(){
 
     BASIC ACCESS:
 
-    ini.value <FILE> <SECTION> <KEY>
+    ini.value <INIFILE> <SECTION> <KEY>
         Get a avlue of a variable in a given section.
 
         Tho shorten ini.value with 3 parameters:
 
-        ini.set <FILE> [<SECTION>]
+        ini.set <INIFILE> [<SECTION>]
 
         or
 
-        ini.set <FILE>
+        ini.set <INIFILE>
         ini.setsection <SECTION>
 
         This sets the ini file and/ or section as default.
@@ -201,21 +214,34 @@ function ini.help(){
 
     OTHER GETTERS:
 
-    ini.sections <FILE>
+    ini.sections <INIFILE>
         Get all sections in the ini file.
-        The <FILE> is not needed if ini.set <FILE> was used before.
+        The <INIFILE> is not needed if ini.set <INIFILE> was used before.
 
-    ini.keys <FILE> <SECTION>
+    ini.keys <INIFILE> <SECTION>
         Get all keys in the given section.
-        The <FILE> is not needed if ini.set <FILE> was used before.
+        The <INIFILE> is not needed if ini.set <INIFILE> was used before.
         The <SECTION> is not needed if ini.setsection <SECTION> was used 
         before.
 
-    ini.dump <FILE>
-        Get a nice overview of the ini file.
+    ini.dump <INIFILE>
+        Get a pretty overview of the ini file.
         You get a colored view of the content and a parsed view of the
         sections and keys + values.
 
+    VALIDATION:
+
+    ini.validate <INIFILE> <VALIDATIONINI> <FLAG>
+        Validate your ini file with the rules of a given validation ini file.
+        The ini for validation contains rules for 
+        * writing sections and keys
+        * sections and keys thet must exist or can exist
+        * describe values of keys to ensure to get vald data (eg a regex)
+        see https://www.axel-hahn.de/docs/bash_iniparser/Validation.html
+        The <FLAG> is optional. By default it is 0 and shows error information
+        only on STDOUT. Set it to 1 to see more output about the validation 
+        process.
+
 EOH
 }
 
@@ -243,7 +269,15 @@ function ini.varexport(){
 }
 
 # validate the ini file
+# param  string  path of ini file to validate
+# param  string  path of ini file with validation rules
+# param  bool    optional: show more output; default: 0
 function ini.validate(){
+
+    function _vd(){
+        test "$bShowAll" -ne "0" && echo "$*"
+    }
+
     local myinifile="$1"
     local myvalidationfile="$2"
     local bShowAll="${3:-0}"
@@ -251,84 +285,147 @@ function ini.validate(){
     local ERROR="\e[1;31mERROR\e[0m"
     local iErr; typeset -i iErr=0
 
+    # TODO: make all used vars local
+
+    _vd "START: Validate ini '${myinifile}'"
+    _vd "       with '${myvalidationfile}'"
     if [ ! -f "${myinifile}" ]; then
+        echo -e "$ERROR: Ini file in first param '${myinifile}' does not exist." >&2
         return 1
     fi
 
     if [ ! -f "${myvalidationfile}" ]; then
-        echo -e "$ERROR: Validation file '${myvalidationfile}' does not exist."
+        echo -e "$ERROR: Validation file in 2nd param '${myvalidationfile}' does not exist." >&2
         return 1
     fi
-    . "${myvalidationfile}" || return 1
-
-    if [ -n "$sectionsMust" ]; then
-            test $bShowAll -ne 0 && echo "--- Validate MUST sections $sectionsMust"
-            for section in $( tr "," " " <<< "$sectionsMust");
-            do
-                if ini.sections "$myinifile" | grep -q "^$section$" ; then
-                    test $bShowAll -ne 0 && echo "OK: Section $section is present."
-                else
-                    echo -e "$ERROR: Section $section is not present."
-                    iErr+=1
-                fi
-            done
+
+    eval "$( ini.varexport "validate_" "$myvalidationfile" )"
+    
+    if [ -z "${validate_sections[*]}" ]; then
+        echo -e "$ERROR: Validation file in 2nd param '${myvalidationfile}' has no section definition [sections]." >&2
+        echo "       Hint: Maybe it is no validation file (yet) or you flipped the parameters." >&2
+        return 1
+    fi
+    if [ -z "${validate_varsMust[*]}${validate_varsCan[*]}" ]; then
+        echo -e "$ERROR: Validation file in 2nd param '${myvalidationfile}' has no key definition [varsMust] and [varsCan]." >&2
+        echo "       Hint: Maybe it is no validation file (yet) or you flipped the parameters." >&2
+        return 1
     fi
 
-    test $bShowAll -ne 0 && echo "--- Validate section names"
+
+    # ----- Check if all MUST sections are present
+    if [ -n "${validate_sections['must']}" ]; then
+        _vd "--- Sections that MUST exist:"
+        for section in $( tr "," " " <<< "${validate_sections['must']}");
+        do
+            if ini.sections "$myinifile" | grep -q "^$section$" ; then
+                _vd "OK: Section [$section] is present."
+            else
+                echo -e "$ERROR: Section [$section] is not present." >&2
+                iErr+=1
+            fi
+        done
+    fi
+
+    # ----- Loop over sections
+    _vd "--- Validate section names"
     for section in $( ini.sections "$myinifile" )
     do
-        if ! grep -Fq ",${section}," <<< ",${sectionsMust},${sectionsCan},"; then
-            echo -e "$ERROR: unknown section name: [$section]"
+        # ----- Check if our section name has the allowed syntax
+        if ! grep -q "${validate_style['section']}" <<< "$section" ; then
+            echo -e "$ERROR: Section [$section] violates style rule '${validate_style['section']}'" >&2
+        fi
+
+        # ----- Check if our sections are in MUST or CAN
+        if ! grep -Fq ",${section}," <<< ",${validate_sections['must']},${validate_sections['must']},"; then
+            echo -e "$ERROR: Unknown section name: [$section] - ist is not listed as MUST nor CAN." >&2
             iErr+=1
         else
-            test $bShowAll -ne 0 && echo "OK: section [$section] is valid... checking its keys..."
-            # TODO: verify values
+            _vd "OK: section [$section] is valid"
+            _vd "  Check keys of section [$section]"
 
-            for mustkey in  $( echo "${varsMust}" | grep "^[/t ]*${section}\." | cut -f 2 -d '.' | cut -f 1 -d ':' ); do
-                keyregex="$( echo $mustkey | sed -e's,\[,\\[,g' )"
-                if ini.keys "$myinifile" "$section" | grep "^${keyregex}$"; then
-                    test $bShowAll -ne 0 && echo "  OK: $section.$mustkey"
+            # ----- Check MUST keys in the current section
+            for myKeyEntry in "${!validate_varsMust[@]}"; do
+                if ! grep -q "^${section}\." <<< "${myKeyEntry}"; then
+                    continue
+                fi
+                mustkey="$( echo "$myKeyEntry" | cut -f2 -d '.')"
+                # TODO
+                keyregex="$( echo "$mustkey" | sed -e's,\[,\\[,g' )"
+                if ini.keys "$myinifile" "$section" | grep -q "^${keyregex}$"; then
+                    _vd "  OK: [$section] -> $mustkey is a MUST"
                 else
-                    echo -e "  $ERROR: A MUST key '$mustkey' was not found im section [$section]."
+                    echo -e "  $ERROR: [$section] -> $mustkey is a MUST key but was not found im section [$section]." >&2
                     iErr+=1
                 fi
+
             done
 
-            for mykey in $(ini.keys "$myinifile" "$section"); do
-                # we need a regex for keys as array eg "file[] = ..."
+            # ----- Check if our keys are MUST or CAN keys
+            for mykey in $( ini.keys "$myinifile" "$section"); do
+
+                if ! grep -q "${validate_style['key']}" <<< "$mykey" ; then
+                    echo -e "$ERROR: Key [$section] -> $mykey violates style rule '${validate_style['key']}'" >&2
+                fi
+
                 keyregex="$( echo "${mykey}" | sed -e's,\[,\\[,g' | sed -e's,\],\\],g' )"
-                if ! echo "
-                ${varsMust}
-                ${varsCan}
-                " | cut -f 1 -d ':' | grep -q "^[/t ]*${section}\.${keyregex}$"; then
-                    echo -e "  $ERROR: invald key name: $section.$mykey"
+
+                local mustKeys
+                mustKeys="$( echo "${!validate_varsMust[@]}" | tr ' ' ',')"
+                local canKeys
+                canKeys="$( echo "${!validate_varsCan[@]}" | tr ' ' ',')"
+
+                if ! grep -Fq ",${section}.$mykey," <<< ",${canKeys},${mustKeys},"; then
+                    echo -e "  $ERROR: [$section] -> $mykey is invalid." >&2
                     iErr+=1
                 else
-                    
-                    check=$(echo "
-                        ${varsMust}
-                        ${varsCan}
-                    " |  grep "^[/t ]*${section}\.${keyregex}[:$]" | cut -f 2 -d ':'  )
-                    if [ -n "$check" ]; then
+
+                    local valKey
+                    valKey="${section}.${mykey}"
+                    if [ -n "${validate_varsCan[$valKey]}" ] && [ -n "${validate_varsMust[$valKey]}" ]; then
+                        echo -e "  $ERROR: '$valKey' is defined twice - in varsMust and varsCan as well. Check validation file '$myvalidationfile'." >&2
+                    fi
+
+                    sValidate="${validate_varsCan[${section}.${mykey}]}"
+                    if [ -z "$sValidate" ]; then
+                        sValidate="${validate_varsMust[${section}.${mykey}]}"
+                    fi
+                    if [ -z "$sValidate" ]; then
+                        _vd "  OK: [$section] -> $mykey exists (no check)"
+                    else
+                        local checkType
+                        local checkValue
+                        local value
+
+                        checkType=$( cut -f 1 -d ':' <<< "$sValidate" )
+                        checkValue=$( cut -f 2- -d ':' <<< "$sValidate" )
                         value="$(ini.value "$myinifile" "$section" "$mykey")"
-                        if ! grep -Eq "^${check}$" <<< "$value" ; then
-                            echo -e "  $ERROR: key name $section.$mykey is valid but value '$value' does NOT match '$check'"
-                        else
-                            test $bShowAll -ne 0 && echo "  OK: key name $mykey is valid and value matches '$check'"
+                        local regex
+                        case $checkType in
+                            'INTEGER') regex="^[1-9][0-9]*$"          ;;
+                            'ONEOF')   regex="^(${checkValue//,/|})$" ;;
+                            'REGEX')   regex="$checkValue"            ;;
+                            *)
+                                echo -e "  $ERROR: ceck type '$checkType' is not supported." >&2
+                        esac
+                        if [ -n "$regex" ]; then
+                            if ! grep -Eq "${regex}" <<< "$value" ; then
+                                echo -e "  $ERROR: [$section] -> $mykey is valid but value '$value' does NOT match '$regex'" >&2
+                            else
+                                _vd "  OK: [$section] -> $mykey is valid and value matches '$regex'"
+                            fi
                         fi
-                    else
-                        test $bShowAll -ne 0 && echo "  OK: key name $mykey is valid"                    
+
                     fi
-                    
                 fi
             done
         fi
     done
 
     if [ $iErr -gt 0 ]; then
-        echo "RESULT: Errors were found for $myinifile"
+        echo "RESULT: Errors were found for $myinifile" >&2
     else
-        test $bShowAll -ne 0 && echo "RESULT: OK, Ini file $myinifile looks fine."
+        _vd "RESULT: OK, Ini file $myinifile looks fine."
     fi
     return $iErr