2 ############################################################
4 # author: CottonCandyOwner(CottonCandyOwner@126.com)
6 ############################################################
7 # Copyright (C) 2022- Free Software Foundation, Inc.
8 # This configure script is free software; the Free Software
9 # Foundation gives unlimited permission to copy, distribute
11 ############################################################
13 # envar is a envrionment variable that consisted by
14 # several part of string with the seperator '::'.
15 # it is used by 'envar' in imi file, or catalog node
17 # it uses ATTR__ prefix to make difference from other
20 ############################################################
25 # @ does it need to add a pfx 'ATTR__' for all envar?
26 # @ add declare/local/global/readonly/export/unset/env/printenv redefine.
27 # testing for them, get the time compare with default cmd. testing
28 # for normal invoking, and the wortest complex condition.
32 # @ name of variable defination
33 # all variable names add a prefix with 'ATTR__', it means the variable is an envar.
34 # all function names add a prefix with 'FUNC::', it means the function is a method.
35 # when the list operation is doing, it can recognize envar and method easilly.
36 # 'FUNC__' is a reference variable prefix. it stored a function name to be invoked.
37 # the normal environment variable print cmd is invoked, it display variables without
38 # 'ATTR__' prefix. this kind of method is used to avoid large number of variables
39 # displayed on terminal.
48 ##############################
49 # section: public comment info
50 ##############################
53 ##############################
54 # section: variable define
55 ##############################
59 # it is defined in shlibinc. use file name as the module domain name.
60 envar_module_domain
=envar
62 CFG_FUNC_NAME_COLON
="true"
66 ##############################
67 # section: private function
68 ##############################
72 ##############################
73 # section: public function
74 ##############################
78 # not all the shell interpreter support function name with char of ':'.
79 # so it is defined as a variable. if the shell program does not support ':',
80 # modify code, and use '__' instead.
81 # defined with '::' can be displayed clearly, and less program processing.
86 # if the shell script interpreter does not support ':', use "_" instead.
92 # fsyntax: envar_get_vname var
93 # fdesc: get vironment variable name string from param which is formatted
94 # as 'AAA::BBB::CCC', translate to 'AAA__BBB__CCC', whatever it is existing.
95 # if null string is used for varname, the script interpreter will
96 # report error, and it is not processed in code to cost down cpu
105 # TBD: if there is a '@' pfx, use as an envar, or treat as a env var first.
106 if [[ "${1:0:1}" == '@' ]]; then
112 # try to match in domain list.
113 if [[ ${name:0:2} != '::' ]]; then
115 for domain
in $envar_module_domain "" $envar_curr_domain $envar_domain_list; do
116 if [[ -n $domain ]]; then
117 vname
="${domain}::$name"
118 vname
="ATTR__${vname//::/__}"
120 vname
="ATTR__${name//::/__}"
122 # dbgoutd "n.${vname}=${!vname}\n"
123 [[ -v "${vname}" ]] && echo "$vname" && return
126 # directly invoking to compactive to general using.
127 [[ -v "${name}" ]] && echo "$name" && return
129 # translate envar var name
130 # dbgoutd "name=$name\n"
132 vname
="ATTR__${vname//::/__}"
133 # dbgoutd "vname=$vname\n"
135 # dbgoutd "1.${vname}=${!vname}\n"
136 [[ -v "$vname" ]] && echo "$vname" && return
139 # if var is not exist, output original name string.
144 # fsyntax: envar_get_fname <var>
145 # fdesc: get function name string wether if it is exist or not.
155 # @ directly function defined by envar_func(), or method function maybe with '::' operator.
156 # @ use envar-var store function name
158 if [[ "${1:0:1}" == '@' ]]; then
164 # try to match in domain list.
165 if [[ ${fname:0:2} != '::' ]]; then
166 if [[ "$CFG_FUNC_NAME_COLON" == "true" ]]; then
167 for domain
in $envar_module_domain "" $envar_curr_domain $envar_domain_list; do
168 [[ -n $domain ]] && domain
="${domain}::"
169 fname
="FUNC::${domain}${name}"
170 # dbgoutd "n.${fname}=${!fname}\n"
171 [[ $
(is_func_defined
$fname) == true
]] && echo "$fname" && return
172 vname
="R${fname//::/__}"
173 [[ $
(is_var_defined
$vname) == true
]] && echo "${!vname}" && return
176 # use name directly without any prefix.
177 # put it in last, because it is few condition
178 # for normal function invoking by 'invoke'.
179 # dbgoutd "0.${name}=${!name}\n"
180 [[ $
(is_func_defined
$name) == true
]] && echo "$name" && return
181 [[ $
(is_var_defined
$name) == true
]] && echo "${!name}" && return
183 # domain list set by using.
184 for domain
in $envar_module_domain "" $envar_curr_domain $envar_domain_list; do
185 [[ -n $domain ]] && domain
="${domain}::"
186 fname
="FUNC__${domain}${name//::/__}"
187 [[ $
(is_func_defined
$fname) == true
]] && echo "$fname" && return
189 [[ $
(is_var_defined
$vname) == true
]] && echo "${!vname}" && return
192 # use name directly without any prefix.
193 [[ $
(is_func_defined
$name) == true
]] && echo "$name" && return
194 vname
="${name//::/__}"
195 [[ $
(is_var_defined
$vname) == true
]] && echo "${!vname}" && return
198 if [[ "$CFG_FUNC_NAME_COLON" == "true" ]]; then
199 fname
="FUNC::${name:2}"
200 [[ $
(is_func_defined
$fname) == true
]] && echo "$fname" && return
201 vname
="R${fname//::/__}"
202 [[ $
(is_var_defined
$vname) == true
]] && echo "${!vname}" && return
204 fname
="FUNC__${name:2//::/__}"
205 [[ $
(is_func_defined
$fname) == true
]] && echo "$fname" && return
207 [[ $
(is_var_defined
$vname) == true
]] && echo "${!vname}" && return
211 # if var is not exist, output original name string.
216 # fsync: envar_mode <mode> <en/dis>
217 # fdesc: enable or disable for some features, such as readonly, associated array.
224 declare -g -a envar_tmp_initval
=
227 # fsyntax: envar_create <envar-name> [= <value>]
228 # fdesc: alloc a envrionment variable, and assign value if
229 # it is needed. var name is consisted by 3 part described
230 # in envar-name paramter.
231 # set envar-var value whether it is exist or not.
232 # it always create envar-var in global domain.
245 # dbgoutd create "$@\n"
246 # eval dbgoutd "\"envar_create \\\"$@\\\"\n\""
247 while [[ ${1: 0:1} == "-" ]]; do
253 # keep array define in $@. $n maybe is a string with blanks.
254 if [[ "$1" =~
"=" ]]; then
256 if [[ "$1" =~
"+=" ]]; then
265 # dbgoutd "initval=$initval\n"
268 if [[ -z "$initval" ]]; then
274 expr="${initval[@]} $@"
275 # dbgoutd "initval=${expr}\n"
276 # dbgoutd "left_char=${initval:0:1}\n"
277 # dbgoutd "right_char=${expr: -1:1}\n"
279 tmp
="${initval:0:1}${expr: -1:1}"
282 initval
="${initval:1}"
283 [[ -z "$initval" ]] && initval
="$1" && shift
286 # dbgoutd "initval=${initval[@]}\n"
288 initval
=( "$initval" "$@" )
290 initval
[$tmp]="${initval[$tmp]:0:-1}"
291 [[ -z "${initval[$tmp]}" ]] && unset initval
[$tmp]
296 warn
"one of '(' or ')' is not found!\n"
300 # normal string value.
301 initval
="$initval $@"
304 elif [[ "${2:0:1}" == "=" ||
"${2:0:2}" == "+=" ]]; then
309 if [[ -z "$initval" ]]; then
312 initval
="$initval $@"
320 # ':::' pfx for global variable define without domain pfx appending.
321 # '::' pfx for global domain without module pfx.
322 if [[ ${name:0:3} == ':::' ]]; then
324 elif [[ ${name:0:2} == '::' ]]; then
325 name
="ATTR__${name:2}"
326 name
="${name//::/__}"
328 tmp
="$(envar_get_vname $name)"
330 if [[ -n $tmp ]]; then
331 # XXX: sometimes, re-create is a normal function feature.
332 #warn "envar '$name' has been created.\n"
333 # dbgoutd "existing $tmp=${!tmp}\n"
336 name
="ATTR__${name//::/__}"
340 expr="declare -g $opt ${name}${operation}${pfx}\"\${initval[@]}\"${sfx}"
348 unset envar_tmp_initval
349 declare -g -a envar_tmp_initval
=
350 if [[ "${initval:0:1}" == '(' && "${initval: -1:1}" == ')' ]]; then
351 # the paramter of '-a' must after others, or others will be reported as an error.
354 read -a envar_tmp_initval
< <(echo "${initval:1:-1}")
358 initval
="\"\${envar_tmp_initval[@]}\""
360 envar_tmp_initval
="${initval#\ }"
361 initval
="\"\${envar_tmp_initval[@]}\""
368 # fsyntax: envar_local <envar-name> [= <value>]
369 # fdesc: it's different from others. it create in current function. delate this
370 # envar-var when function return. and the access property is global. it
371 # can be accessed in any function it invoked. so it can be used as a paramter
384 while [[ ${expr:0:1} == "-" ]]; do
385 if [[ ${expr:0:2} == "-A" ]]; then
388 elif [[ ${expr:0:2} == "-r" ]]; then
392 expr=${expr#-[^\ ]\ }
397 if [[ "$expr" =~
"=" ]]; then
402 initval
="${initval#\ }"
404 if [[ ${name:-1:1} == "+" ]]; then
415 [[ ${name:0:2} == '::' ]] && name
=${name:2}
417 expr="$(envar_get_vname $name)"
418 if [[ -n $expr ]]; then
420 warn
"envar '$name' has been created.\n"
422 name
="ATTR__${name//::/__}"
425 unset envar_tmp_initval
426 declare -g -a envar_tmp_initval
=
427 if [[ "${initval:0:1}" == '(' && "${initval: -1:1}" == ')' ]]; then
428 # the paramter of '-a' must after others, or others will be reported as an error.
429 read -a envar_tmp_initval
< <(echo "${initval:1:-1}")
432 initval
="\"\${envar_tmp_initval[@]}\""
434 envar_tmp_initval
="${initval#\ }"
435 initval
="\"\${envar_tmp_initval[@]}\""
438 expr="declare -l $opt ${name}${operation}${pfx}${initval}${sfx}"
440 [[ -n $name ]] && eval "${expr}"
444 # fsync: envar_delete var
445 # fdesc: create the envar-var by paramter string.
448 local name
=$
(envar_get_vname
$1)
451 [[ "$1" == "::" ]] && eval unset \
${!ATTR_*} && return
453 [[ -n ${!name} ]] && unset $name && return
455 eval envarlist
=\
${!${name}*}
456 for name
in $envarlist; do
462 # fsyntax: envar_create <envar-name> [= <value>]
463 # fdesc: it's different from create, it create envar-var in current module domain.
464 # invoke envar_create() in function, and invoke envar_decleare() in global define
472 if [[ ${name:0:2} =~
"-A" ]]; then
478 if [[ ${name:0:2} != '::' && -n ${envar_module_domain} ]]; then
479 # current module domain define.
480 envar_create
$opt ${envar_module_domain}::"$@"
483 envar_create
$opt "$@"
488 # fsync: envar_array var[cnt1][cnt2]
489 # fdesc: create the envar-var by paramter string.
497 # fsync: envar_readonly var[cnt1][cnt2]
498 # fdesc: create readonly envar.
505 # fsyntax: envar_dup <envar-name> <new-envar-name>
506 # fdesc: copy the content of envar variables.
510 local name
=$
(envar_get_vname
$1)
514 [[ -z $name ]] && return
517 for name
in $envarlist; do
518 eval new
=${name//${name}_/${2}_}
519 envar_create
$new = "$(envar_get $name)"
524 # fsync: envar_rename var new-var
525 # fdesc: create the envar-var by paramter string.
528 local name
=$
(envar_get_vname
$1)
532 [[ -z $name ]] && return
535 for name
in $envarlist; do
536 eval new
=${name//${name}_/${2}_}
537 envar_create
$new = "$(envar_get $name)"
543 # fsync: envar_export var
544 # fdesc: export variable.
547 local name
=$
(envar_get_vname
$1)
550 [[ -n ${!name} ]] && unset $name && return
552 eval envarlist
=\
${!${name}*}
553 for name
in $envarlist; do
559 # fsync: envar_unexport var
560 # fdesc: export variable.
563 local name
=$
(envar_get_vname
$1)
566 [[ -n ${!name} ]] && unset $name && return
568 eval envarlist
=\
${!${name}*}
569 for name
in $envarlist; do
575 # fsyntax: envar_array_get <envar-name>
576 # fdesc: get the value of envar var.
580 local name
="$(envar_get_vname $1)[@]"
582 # dbgoutd "envar_array_get() $1 ==> $name\n"
583 [[ -z $name ]] && return
585 [[ -n ${!name} ]] && echo -e "${!name}"
589 # fsyntax: envar_array_cnt <envar-name>
590 # fdesc: get the count of envar array.
594 local name
="$(envar_get_vname $1)[@]"
596 # dbgoutd "envar_array_get() $1 ==> $name\n"
597 [[ -z $name ]] && return
599 eval echo -e "\${#${name}}"
603 # fsyntax: envar_get <envar-name>
604 # fdesc: get the value of envar var.
608 local name
=$
(envar_get_vname
$1)
612 # dbgoutd "name=$name\n"
613 # dbgoutd "envar_get() $1 ==> $name\n"
614 [[ -z $name ]] && return
617 [[ $
(is_func_defined
${name}_on_get) == true ]] && ${name}_on_get ${name} "${operation}" "${pfx}${initval}${sfx}"
619 # XXX: here the '\n' maybe not append.
620 [[ -n ${!name} ]] && echo -ne "${!name}\n"
624 # fsyntax: envar_set <envar-name> [= <value>]
625 # fdesc: set envar-var value if it is exist.
637 if [[ "$expr" =~ "=" ]]; then
642 initval="${initval#\ }"
644 if [[ ${name:-1:1} == "+" ]]; then
655 [[ ${name:0:2} == '::' ]] && name=${name:2}
657 expr="$
(envar_get_vname
$name)"
658 if [[ -z $expr ]]; then
659 warn "envar
'$name' has not been created.
\n"
662 # name="ATTR__
${name//::/__}"
666 unset envar_tmp_initval
667 declare -g -a envar_tmp_initval=
668 if [[ "${initval:0:1}" == '(' && "${initval: -1:1}" == ')' ]]; then
669 # TBD: here should be improved.
670 # the paramter of '-a' must after others, or others will be reported as an error.
671 read -a envar_tmp_initval < <(echo "${initval:1:-1}")
674 initval="\"\
${envar_tmp_initval[@]}\""
676 envar_tmp_initval="${initval#\ }"
677 initval="\"\
${envar_tmp_initval[@]}\""
680 expr="declare -g ${name}${operation}${pfx}${initval}${sfx}"
682 # dbgoutd "envar_tmp_initval
=${envar_tmp_initval[@]}\n"
683 # dbgoutd "expr=$expr\n"
685 [[ $(is_func_defined ${name}_on_set) == true ]] && ${name}_on_set ${name} "${operation}" "${pfx}${initval}${sfx}"
687 [[ -n $name ]] && eval "${expr}"
688 # eval dbgoutd "${name}=\${${name}[@]}\n"
693 # fsync: envar_is_valid var
694 # fdesc: check the envar if it is exist.
695 # or use [[ -v ATTR_XXX__domain__subitem ]] in code.
698 if [[ -n "$(envar_get_vname $1)" ]]; then
706 # fsync: envar_type <envar-name>
707 # fdesc: it check the type of envar, output 'env', 'var', 'func', 'vfunc'.
712 [[ ${1: 0:3} == ':::' && -v ${1:3} ]] && echo env
&& return
714 vname
="$(envar_get_vname $1)"
716 # dbgoutd "vname=$vname\n"
717 if [[ -n "${vname}" ]]; then
718 if [[ -n "$(envar_get_fname ${!vname})" ]]; then
723 elif [[ -n "$(envar_get_fname ${1})" ]]; then
731 # fsync: envar_listvar
732 # fdesc: list all env-var for envar in current process.
735 echo "${!ATTR__*}" |
tr -s ' ' $
'\n'
740 # fdesc: list all envar-var in current process.
747 echo "${data//__/::}"
748 done < <(echo "${!ATTR__*}" |
tr -s ' ' $
'\n')
752 # fsync: envar_listofvar var
753 # fdesc: list envar under a var.
758 local vprefix
="${1//::/__}"
760 if [[ $1 != "::" ]]; then
761 [[ ${vprefix:0:2} != '__' ]] && vprefix="__${envar_module_domain}__${vprefix}__
"
765 [[ -z $data ]] && continue
766 # eval vname=\${data//ATTR$vprefix}
769 done < <(eval "echo \"\
${!ATTR$vprefix*}\"" | tr -s ' ' $'\n')
773 # fsync: envar_listof var
774 # fdesc: list envar under a var.
779 local vprefix="${1//::/__}"
781 if [[ $1 != "::" ]]; then
782 if [[ ${vprefix:0:2} != '__' ]]; then
783 vprefix="__
${envar_module_domain}__
${vprefix}__
"
785 vprefix="${vprefix}__
"
790 [[ -z $data ]] && continue
791 eval vname=\${data//ATTR$vprefix}
792 vname="${vname//__/::}"
795 done < <(eval "echo \"\
${!ATTR$vprefix*}\"" | tr -s ' ' $'\n')
799 # fsync: envar_listunder var
800 # fdesc: list envar just under a var directly.
808 [[ ! "${list}" =~ :: ]] && echo "${list}"
809 done < <(envar_listof $1) | sort -u
813 # fsync: envar_foreach venvar proc
814 # fdesc: ergodic the member var under envar-var.
819 local vprefix="${1//::/__}"
821 # [[ -z $2 ]] && warn "proc
function does not spedified
in paramter.
\n" && return
822 # [[ $(is_func_defined $2) == false ]] && warn "proc
function '$2' does not defined.
\n" && return
824 if [[ $1 != "::" ]]; then
825 [[ ${vprefix:0:2} != '__' ]] && vprefix="__${envar_module_domain}__${vprefix}__"
829 [[ -z $data ]] && continue
830 eval vname
=\
${data//ATTR$vprefix}
831 vname
="${vname//__/::}"
833 $2 "${vname}" "${data}"
834 done < <(eval "echo \"\${!ATTR$vprefix*}\"" |
tr -s ' ' $
'\n')
838 # fsync: envar_expr venvar=xxx
839 # envar_expr ::var=venvar
840 # fdesc: dispatch the calculation expr of envar-var.
847 ##################################
849 ##################################
853 # 'type' maybe called with 'sectype', it means a type define for section in imi file.
854 # it will mix with other program language by using 'type'.
865 # define envar under a type.
872 # define a entity by the specified type.
879 # define envar under a type.
886 ###########################################################################
888 ###########################################################################
892 # fsync: envar_alias func_var func-name
893 # fdesc: create the envar-var by paramter string.
894 # var::sub::method ()
902 # fsync: envar_vfunc var::sub::method()
903 # fdesc: virtual function defination. it is stored in a reference envar variable.
910 # fsync: envar_func var::sub::method()
911 # fdesc: create the envar-var by paramter string.
912 # # 数组中的max-cnt,或结构体的成员变量数
913 # 或命名为method(),表示一个method的定义。
922 # it can use char ":" in function name
934 if [[ ${vname:0:2} != '::' ]]; then
935 fname
="$envar_module_domain::$fname"
939 for (( i
=${#param[@]}-1; i
>=0; i--
)); do
941 for (( j
=${#tmp[@]}-1; j
>=0; j--
)); do
942 [[ -z ${tmp[$j]} ]] && continue
944 # ignor var qualifier
945 if [[ -z ${param_name_list[$i]} ]]; then
946 param_name_list
[$i]=${tmp[$j]}
947 elif [[ -z ${param_type_list[$idx]} ]]; then
959 `for (( i=${#param_name_list[@]}-1;i >= 0; i-- )); do
960 echo -ne \"local \${param_name_list[\$i]}=\\\${$(( i + 1 ))}\";
966 # fsync: envar_invoke param_list
967 # envar_invoke [[param_list, ...]]
968 # fdesc: create the envar-var by paramter string.
981 name
=$
(envar_get_fname
$1)
982 [[ -z $name ]] && $name "${cmd[@]}" && return $?
985 # 设置作用域。::表示global起始的作用域,未添加时,使用using作用域中的pfx。..表示回退一级作用域,以::代替/,用于多级作用域表示。
988 # fsync: envar_domain domain
989 # fdesc: switch 'CURRENT' domain as a dir operation.
992 if [[ ${1:0:2} == '::' ]]; then
993 envar_curr_domain
="${1:2}"
994 elif [[ ${1:0:2} == '..' ]]; then
995 envar_curr_domain
="${envar_curr_domain%::*}"
996 elif [[ -z ${1} ]]; then
999 envar_curr_domain
="$envar_curr_domain::$1"
1004 # fsync: envar_using domain
1005 # fdesc: append domain prefix.
1008 envar_domain_list
+="$1 "
1012 # fsync: envar_unuse domain
1013 # fdesc: delete domain prefix.
1016 if [[ "$envar_curr_domain" =~
'$1' ]]; then
1017 envar_domain_list
="${envar_curr_domain//$1/}"
1024 ###############################################################################################
1027 ##############################
1028 # section: file tail
1029 ##############################
1033 # fsync: envar_listofvar var
1034 # fdesc: list envar under a var.
1039 local vprefix
="${1//::/__}"
1041 # if [[ $1 != "::" ]]; then
1042 [[ ${vprefix:0:2} != '__' ]] && vprefix="__${envar_module_domain}__${vprefix}"
1045 [[ -v "ATTR__T
${vprefix}" ]] && echo "${1}"
1047 # echo "vprefix
=ATTR__T
$vprefix"
1048 # eval echo "list
=\
${!ATTR__T$vprefix*}"
1051 [[ -z $data ]] && continue
1053 [[ $data =~ ^ATTR__T[DVFR]?${vprefix}(.*)$ ]] && vname=${BASH_REMATCH[1]}
1054 # eval vname=\${data#ATTR__T}
1055 # eval vname=\${data#^__${vprefix}/}
1056 [[ ${vname:0:2} == '__' ]] && vname=${vname:2}
1057 # this statement does not works.
1058 # vname="${vname//[[:alnum:]]*__/ }"
1059 [[ -n "${vname}" ]] && sed -e "s
/[[:alnum
:]]*__
/XXX
::/g
" <<< "${vname}"
1060 # [[ -n "${vname}" ]] && echo " ${vname//__/::}"
1061 done < <(eval "echo \"\
${!ATTR__T$vprefix*} \${!ATTR__TD$vprefix*} \${!ATTR__TV$vprefix*} \${!ATTR__TF$vprefix*} \${!ATTR__TR$vprefix*} \"" | tr -s ' ' $'\n')
1065 [[ -z $data ]] && continue
1066 [[ $data =~ ^type ]] && continue
1068 #eval vname=\${data//ATTR__T$vprefix}
1070 done < <(eval "echo \"\
${!ATTR__T$vprefix}\"" | tr -s ' ' $'\n')
1072 #echo ${vname//[[:alnum:]]*__/$'\t'}
1073 #echo ${vname//[[:alnum:]]*__/ }
1076 # fsync: envar_listofvar var file
1077 # fdesc: list envar under a var.
1078 envar_listofvar_dump2file ()
1082 local vprefix="${1//::/__}"
1084 if [[ $1 != "::" ]]; then
1085 [[ ${vprefix:0:2} != '__' ]] && vprefix="__${envar_module_domain}__${vprefix}__"
1088 eval "echo \"\${!ATTR$vprefix*}\"" |
tr -s ' ' $
'\n' |
1090 [[ -z $data ]] && continue
1091 eval vname
=\
${data//ATTR$vprefix}
1098 # fsync: envar_memberof var
1099 # fdesc: list the sub envar-var under a domain or an envar-var.
1100 # # 结构体变量中的member列表,包括函数