Skip to content
Snippets Groups Projects
Commit f65defaf authored by Axel Hahn's avatar Axel Hahn
Browse files

update ini.class.sh

parent d2937536
Branches
No related tags found
1 merge request!129Db Profiles
......@@ -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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment