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 @@ ...@@ -16,6 +16,8 @@
# 2024-02-12 v0.4 rename local varables # 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-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-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= INI_FILE=
...@@ -32,7 +34,7 @@ function ini.set(){ ...@@ -32,7 +34,7 @@ function ini.set(){
INI_FILE= INI_FILE=
INI_SECTION= INI_SECTION=
if [ ! -f "$1" ]; then if [ ! -f "$1" ]; then
echo "ERROR: file does not exist: $1" echo "ERROR: file does not exist: $1" >&2
exit 1 exit 1
fi fi
INI_FILE="$1" INI_FILE="$1"
...@@ -45,14 +47,14 @@ function ini.set(){ ...@@ -45,14 +47,14 @@ function ini.set(){
# param string section # param string section
function ini.setsection(){ function ini.setsection(){
if [ -z "$INI_FILE" ]; then 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 exit 1
fi fi
if [ -n "$1" ]; then if [ -n "$1" ]; then
if ini.sections "$INI_FILE" | grep "^${1}$" >/dev/null; then if ini.sections "$INI_FILE" | grep "^${1}$" >/dev/null; then
INI_SECTION=$1 INI_SECTION=$1
else else
echo "ERROR: Section [$1] does not exist in [$INI_FILE]." echo "ERROR: Section [$1] does not exist in [$INI_FILE]." >&2
exit 1 exit 1
fi fi
fi fi
...@@ -75,7 +77,7 @@ function ini.sections(){ ...@@ -75,7 +77,7 @@ function ini.sections(){
function ini.section(){ function ini.section(){
local myinifile=${1:-$INI_FILE} local myinifile=${1:-$INI_FILE}
local myinisection=${2:-$INI_SECTION} local myinisection=${2:-$INI_SECTION}
sed -e "0,/^\[${myinisection}\]/ d" -e '/^\[/,$ d' $myinifile \ sed -e "0,/^\[${myinisection}\]/ d" -e '/^\[/,$ d' "$myinifile" \
| grep -v "^[#;]" \ | grep -v "^[#;]" \
| sed -e "s/^[ \t]*//g" -e "s/[ \t]*=[ \t]*/=/g" | sed -e "s/^[ \t]*//g" -e "s/[ \t]*=[ \t]*/=/g"
} }
...@@ -110,12 +112,11 @@ function ini.value(){ ...@@ -110,12 +112,11 @@ function ini.value(){
local out local out
regex="${myvarname//[^a-zA-Z0-9:()]/.}" regex="${myvarname//[^a-zA-Z0-9:()]/.}"
out=$(ini.section "${myinifile}" "${myinisection}" \ out=$(ini.section "${myinifile}" "${myinisection}" \
| sed "s,^[\ \t]*,,g" \ | sed -e "s,^[[:space:]]*,,g" -e "s,[[:space:]]*=,=,g" \
| sed "s,[\ \t]*=,=,g" \
| grep -F "${myvarname}=" \ | grep -F "${myvarname}=" \
| grep "^${regex}=" \ | grep "^${regex}=" \
| cut -f 2- -d "=" \ | 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 )" grep "\[\]$" <<< "$myvarname" >/dev/null || out="$( echo "$out" | tail -1 )"
...@@ -137,26 +138,38 @@ ini.dump() { ...@@ -137,26 +138,38 @@ ini.dump() {
echo "|" echo "|"
echo -e "+----------------------------------------\e[0m" echo -e "+----------------------------------------\e[0m"
echo -e "\e[34m" echo -e "\e[34m"
cat "$myinifile" | sed "s,^, ,g" sed "s,^, ,g" "${myinifile}"
echo -e "\e[0m" echo -e "\e[0m"
echo " Parsed data:" echo " Parsed data:"
echo echo
ini.sections "$myinifile" | while read -r myinisection; do ini.sections "$myinifile" | while read -r myinisection; do
echo -e " --+-- section \e[35m[$myinisection]\e[0m" if ! ini.keys "$myinifile" "$myinisection" | grep -q "."; then
echo " |" echo -e " ----- section \e[35m[$myinisection]\e[0m"
ini.keys "$myinifile" "$myinisection" | while read -r mykey; do else
value="$(ini.value "$myinifile" "$myinisection" "$mykey")" echo -e " --+-- section \e[35m[$myinisection]\e[0m"
# printf " %-15s => %s\n" "$mykey" "$value" echo " |"
printf " \`---- %-20s => " "$mykey" ini.keys "$myinifile" "$myinisection" | while read -r mykey; do
echo -e "\e[1;36m$value\e[0m" value="$(ini.value "$myinifile" "$myinisection" "$mykey")"
done # printf " %-15s => %s\n" "$mykey" "$value"
printf " \`---- %-20s => " "$mykey"
echo -e "\e[1;36m$value\e[0m"
done
fi
echo echo
done done
echo echo
} }
function ini.help(){ function ini.help(){
# local _self
# if _is_sourced; then
# _self="ini."
# else
# _self="$( basename "$0" ) "
# fi
cat <<EOH cat <<EOH
INI.CLASS.SH INI.CLASS.SH
...@@ -180,16 +193,16 @@ function ini.help(){ ...@@ -180,16 +193,16 @@ function ini.help(){
BASIC ACCESS: BASIC ACCESS:
ini.value <FILE> <SECTION> <KEY> ini.value <INIFILE> <SECTION> <KEY>
Get a avlue of a variable in a given section. Get a avlue of a variable in a given section.
Tho shorten ini.value with 3 parameters: Tho shorten ini.value with 3 parameters:
ini.set <FILE> [<SECTION>] ini.set <INIFILE> [<SECTION>]
or or
ini.set <FILE> ini.set <INIFILE>
ini.setsection <SECTION> ini.setsection <SECTION>
This sets the ini file and/ or section as default. This sets the ini file and/ or section as default.
...@@ -201,21 +214,34 @@ function ini.help(){ ...@@ -201,21 +214,34 @@ function ini.help(){
OTHER GETTERS: OTHER GETTERS:
ini.sections <FILE> ini.sections <INIFILE>
Get all sections in the ini file. 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. 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 The <SECTION> is not needed if ini.setsection <SECTION> was used
before. before.
ini.dump <FILE> ini.dump <INIFILE>
Get a nice overview of the ini file. Get a pretty overview of the ini file.
You get a colored view of the content and a parsed view of the You get a colored view of the content and a parsed view of the
sections and keys + values. 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 EOH
} }
...@@ -243,7 +269,15 @@ function ini.varexport(){ ...@@ -243,7 +269,15 @@ function ini.varexport(){
} }
# validate the ini file # 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 ini.validate(){
function _vd(){
test "$bShowAll" -ne "0" && echo "$*"
}
local myinifile="$1" local myinifile="$1"
local myvalidationfile="$2" local myvalidationfile="$2"
local bShowAll="${3:-0}" local bShowAll="${3:-0}"
...@@ -251,84 +285,147 @@ function ini.validate(){ ...@@ -251,84 +285,147 @@ function ini.validate(){
local ERROR="\e[1;31mERROR\e[0m" local ERROR="\e[1;31mERROR\e[0m"
local iErr; typeset -i iErr=0 local iErr; typeset -i iErr=0
# TODO: make all used vars local
_vd "START: Validate ini '${myinifile}'"
_vd " with '${myvalidationfile}'"
if [ ! -f "${myinifile}" ]; then if [ ! -f "${myinifile}" ]; then
echo -e "$ERROR: Ini file in first param '${myinifile}' does not exist." >&2
return 1 return 1
fi fi
if [ ! -f "${myvalidationfile}" ]; then 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 return 1
fi fi
. "${myvalidationfile}" || return 1
eval "$( ini.varexport "validate_" "$myvalidationfile" )"
if [ -n "$sectionsMust" ]; then
test $bShowAll -ne 0 && echo "--- Validate MUST sections $sectionsMust" if [ -z "${validate_sections[*]}" ]; then
for section in $( tr "," " " <<< "$sectionsMust"); echo -e "$ERROR: Validation file in 2nd param '${myvalidationfile}' has no section definition [sections]." >&2
do echo " Hint: Maybe it is no validation file (yet) or you flipped the parameters." >&2
if ini.sections "$myinifile" | grep -q "^$section$" ; then return 1
test $bShowAll -ne 0 && echo "OK: Section $section is present." fi
else if [ -z "${validate_varsMust[*]}${validate_varsCan[*]}" ]; then
echo -e "$ERROR: Section $section is not present." echo -e "$ERROR: Validation file in 2nd param '${myvalidationfile}' has no key definition [varsMust] and [varsCan]." >&2
iErr+=1 echo " Hint: Maybe it is no validation file (yet) or you flipped the parameters." >&2
fi return 1
done
fi 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" ) for section in $( ini.sections "$myinifile" )
do do
if ! grep -Fq ",${section}," <<< ",${sectionsMust},${sectionsCan},"; then # ----- Check if our section name has the allowed syntax
echo -e "$ERROR: unknown section name: [$section]" 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 iErr+=1
else else
test $bShowAll -ne 0 && echo "OK: section [$section] is valid... checking its keys..." _vd "OK: section [$section] is valid"
# TODO: verify values _vd " Check keys of section [$section]"
for mustkey in $( echo "${varsMust}" | grep "^[/t ]*${section}\." | cut -f 2 -d '.' | cut -f 1 -d ':' ); do # ----- Check MUST keys in the current section
keyregex="$( echo $mustkey | sed -e's,\[,\\[,g' )" for myKeyEntry in "${!validate_varsMust[@]}"; do
if ini.keys "$myinifile" "$section" | grep "^${keyregex}$"; then if ! grep -q "^${section}\." <<< "${myKeyEntry}"; then
test $bShowAll -ne 0 && echo " OK: $section.$mustkey" 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 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 iErr+=1
fi fi
done done
for mykey in $(ini.keys "$myinifile" "$section"); do # ----- Check if our keys are MUST or CAN keys
# we need a regex for keys as array eg "file[] = ..." 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' )" keyregex="$( echo "${mykey}" | sed -e's,\[,\\[,g' | sed -e's,\],\\],g' )"
if ! echo "
${varsMust} local mustKeys
${varsCan} mustKeys="$( echo "${!validate_varsMust[@]}" | tr ' ' ',')"
" | cut -f 1 -d ':' | grep -q "^[/t ]*${section}\.${keyregex}$"; then local canKeys
echo -e " $ERROR: invald key name: $section.$mykey" canKeys="$( echo "${!validate_varsCan[@]}" | tr ' ' ',')"
if ! grep -Fq ",${section}.$mykey," <<< ",${canKeys},${mustKeys},"; then
echo -e " $ERROR: [$section] -> $mykey is invalid." >&2
iErr+=1 iErr+=1
else else
check=$(echo " local valKey
${varsMust} valKey="${section}.${mykey}"
${varsCan} if [ -n "${validate_varsCan[$valKey]}" ] && [ -n "${validate_varsMust[$valKey]}" ]; then
" | grep "^[/t ]*${section}\.${keyregex}[:$]" | cut -f 2 -d ':' ) echo -e " $ERROR: '$valKey' is defined twice - in varsMust and varsCan as well. Check validation file '$myvalidationfile'." >&2
if [ -n "$check" ]; then 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")" value="$(ini.value "$myinifile" "$section" "$mykey")"
if ! grep -Eq "^${check}$" <<< "$value" ; then local regex
echo -e " $ERROR: key name $section.$mykey is valid but value '$value' does NOT match '$check'" case $checkType in
else 'INTEGER') regex="^[1-9][0-9]*$" ;;
test $bShowAll -ne 0 && echo " OK: key name $mykey is valid and value matches '$check'" '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 fi
else
test $bShowAll -ne 0 && echo " OK: key name $mykey is valid"
fi fi
fi fi
done done
fi fi
done done
if [ $iErr -gt 0 ]; then if [ $iErr -gt 0 ]; then
echo "RESULT: Errors were found for $myinifile" echo "RESULT: Errors were found for $myinifile" >&2
else else
test $bShowAll -ne 0 && echo "RESULT: OK, Ini file $myinifile looks fine." _vd "RESULT: OK, Ini file $myinifile looks fine."
fi fi
return $iErr return $iErr
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment