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 # this file define a cmd called 'include' which is used
14 # to include a shlib file.
15 # it define a shlib version variable SHLIB_VERSION, and
16 # ROOTFS to store root path in paticulor enviroument.
17 # sometimes, user need file include feature like shlib,
18 # so it define a cmd called 'define_include' to provide this
20 # when i use 'source' in function, it can not load global
21 # variables in sourced file, so, this cmd is defined as an
23 # when shlib code need to be updated in memory, reloadshlib()
24 # is used to do this work.
25 # shlib is included unique, if the shlib loaded in system/bash
26 # init script, and the global variable should be re-init in
27 # every program. so, cmd 'uniqlib' and 'endlib' is defined,
28 # try to load part of lib unique, and others executed every
29 # time. this feature have not been implemented.
30 ############################################################
34 # @ trim code & cmnt, put cmnt into design doc.
35 # @ combine include alias with define_include string.
37 # @ debug info output setting by global variable.
38 # @ testing for load in different process.
40 # @ diff list by listvar_diff(), trim code.
44 # @ include/load/unload/reload
45 # include/load, similar with it in C. include file in
46 # $PWD, or global include path.
47 # # reloading/re-including for same file in different path string.
48 # @ PROG_GVAR_INIT/PROG_INIT/uniqlib
49 # # uniq-include in nestly including.
50 # # compactly load in sub-script-proc.
51 # @ SHLIB_INC_LIST/SHLIB_LIST,
52 # nest_level/nest_level_shlib/shlib_load_state,
53 # inc_flag/last_inc_flag,
54 # for nestly including/loading.
56 # @ if lib in different lib path with same name, they might be mixed.
57 # @ include ./scripts/uniq.shlib
59 # this will record different lib flag in SHLIB_INC_LIST.
60 # maybe use full-path-name will resolve this problem.
63 # @ [shlibinc] binary shlib check and load.
64 # for shlibinc, add a func/alias to check and load binary shlib.
65 # at the beginning of shlib src file, add a binary lib checking cmd. if the
66 # shlib implemented by a binary lib, load it first, and do not load script code
71 # @ SHLIB_VERSION, shlib version infomation.
72 # @ include <shlib-file>, used to include a shlib in the process of current program.
73 # it will be uniq included in a process. once include, does not need to
74 # be 'source' again. but it still need to be included in a new sub-script
76 # @ load/unload <shlib-file>, used to load a shlib in system, or current session,
77 # or current process. the difference with include is that, it recode the
78 # global var & func & alias cmd in exported env var, and set them with
79 # export attribute. when the shlib would be load in a new script program,
80 # it still keep load content.
81 # @ reload <shlib-file>, used to load a shlib again if shlib is updated.
82 # @ PROG_GVAR_INIT <libname>, global variable init in shlib, when the lib file
84 # @ GVAR_INIT <libname>, global variable first init in shlib.
85 # @ uniqlib <libname>, skip loading the code after this cmd, if the shlib has
88 # # get_shlib_path, print shlib one path string by one line.
89 # # get_shlib_path_var <var-name>, get the shlib path in var array.
90 # # set_shlib_path <PATH>, set whole shlib path string.
91 # # add_shlib_path <PATH>, append path to shlib path.
92 # # del_shlib_path <PATH>, delete path by specified string.
93 # # define_include <> <> <> <>, define a include cmd for a kind of lib file.
97 # enable alias feature in script.
98 shopt -s expand_aliases
100 # init ROOTFS if it is not /
101 if [[ ! -d $ROOTFS ]]; then
102 TMP_DIR
=`dirname $(which ls)`/..
103 TMP_DIR
=`cd $TMP_DIR; pwd; cd - > /dev/null`
104 ROOTFS
=${ROOTFS:-$TMP_DIR}
109 # save current process id every time when this file is sourced in a program.
114 # shlib module name stack.
116 if [[ ! -v SHLIB_IDX ||
-z $SHLIB_IDX ]]; then
117 declare -g SHLIB_IDX
=0
118 declare -g SHLIB_MODULE
=${BASH_SOURCE[1]##*\/}
119 SHLIB_MODULE
=${SHLIB_MODULE^^}
123 ##############################
124 # section: public comment info
125 ##############################
128 #echo SHLIB_VERSION=$SHLIB_VERSION
130 ##############################
131 # section: variable define
132 ##############################
135 # todo: comment this code, exported function cannot be used in sub-process.
138 # unique executing judged by shlib version variable.
139 #if [[ -n $SHLIB_VERSION ]]; then
141 # invoke global var init if this script file is invoked in a shlib
143 # [[ -n $1 ]] && PROG_GVAR_INIT $1
145 # echo shlibinc has been loaded, skip to save cpu cost.
148 # shlibinc only could be used by source
149 # use return to exit from current script file.
157 # if defined as exported var, it can be used for feature of one time code loading.
158 # but this feature can not works.
161 SHLIB_VERSION
="0.0.1"
165 # it stored shlib paths like enviroument variable 'PATH'.
167 SHLIB_PATH
=${SHLIB_PATH:-`echo $ROOTFS/usr/shlib:$ROOTFS/usr/libexec/dvar/shlib`}
171 # an array of SHLIB_PATH path.
172 if [[ -z $path_list ]]; then
175 path_list
=( $SHLIB_PATH )
180 # initialization of vch_progstdin should be putted here instead of stdio.shlib.
182 shlibinc__get_file_top_valid_id
()
187 for (( i
=$
((i-1
)); i
>0; i--
)); do
188 [[ ! -e /proc
/self
/fd
/$i ]] && echo $i && return
192 shlibinc_onetime_init
()
194 [[ "$shlibinc_onetime_init_flag" == 1 ]] && return
195 shlibinc_onetime_init_flag
=1
198 [[ -z "$vch_null" ]] &&
199 vch_null
=$
(shlibinc__get_file_top_valid_id
) &&
200 eval "exec $vch_null<>/dev/null"
202 [[ -z "$vch_progstdin" ]] &&
203 vch_progstdin
=$
(shlibinc__get_file_top_valid_id
) &&
204 eval "exec $vch_progstdin<&0"
205 [[ -z "$vch_progstdout" ]] &&
206 vch_progstdout
=$
(shlibinc__get_file_top_valid_id
) &&
207 eval "exec $vch_progstdout>&1"
208 [[ -z "$vch_progstderr" ]] &&
209 vch_progstderr
=$
(shlibinc__get_file_top_valid_id
) &&
210 eval "exec $vch_progstderr>&2"
212 grep -e "^pipe:" << EOF
213 `readlink /proc/self/fd/$vch_progstdin`
215 [[ $?
== 0 ]] && eval "exec $vch_progstdin>&$vch_null"
217 grep -e "^pipe:" << EOF
218 `readlink /proc/self/fd/$vch_progstdout`
220 [[ $?
== 0 ]] && eval "exec $vch_progstdout>&$vch_null"
222 grep -e "^pipe:" << EOF
223 `readlink /proc/self/fd/$vch_progstderr`
225 [[ $?
== 0 ]] && eval "exec $vch_progstderr>&$vch_null"
229 shlibinc_onetime_init
232 # @ include时,判断SHLIB_LIST,已include,skip。首次include中,调用_init()函数,设置SHLIB_LIST。
234 # # 判断SHLIB_INC_LIST,已load,且判断SHLIB_LIST中未load,只调用_init()进行初始化+ 判断SHLIB_INC_LIST,已load,且判断SHLIB_LIST中已load,skip
235 # # 其它,首次load时,调用_init()函数,设置SHLIB_INC_LIST和当前进程的SHLIB_LIST。SHLIB_LIST在创建新进程时不export。
239 # fsyntax: decl_shlib_var <var-name>
240 # fdesc: check exist before var declare, and add SHLIB__ prefix.
244 [[ ! -v SHLIB__
${1^^} ]] && declare -g SHLIB__
${1^^}
249 # LIST variable have not been used
251 if [[ ! -v SHLIB_INC_LIST
]]; then
252 declare -g SHLIB_INC_LIST
=${SHLIB_INC_LIST=""}
254 if [[ ! -v SHLIB_LIST
]]; then
255 declare -g -x SHLIB_LIST
=${SHLIB_LIST=""}
257 #SHLIB_LIST=${SHLIB_LIST=""}
260 [[ ! -v nest_level
]] && declare -g nest_level
=0
262 [[ ! -v nest_level_shlib
]] && declare -g -a nest_level_shlib
[0]=""
265 [[ ! -v shlib_load_state
]] && declare -g -a shlib_load_state
[0]=0
267 # do not append -x attr, it should be resetted in sub-process.
268 [[ ! -v loading_flag
]] && declare -g -a loading_flag
[0]=0
270 # TBD: this var should be used as a load type for shlib,
271 # code in shlib use it to set different variable type, -x or not.
272 [[ ! -v inc_flag
]] && declare -g -a inc_flag
=""
273 [[ ! -v last_inc_flag
]] && declare -g last_inc_flag
=""
290 # nest_level_shlib[], similar with BASH_SOURCE, and used for nestly sourcing.
291 # shlib_load_state[], used for nestly sourcing.
292 # loading_flag[], load/include for current nest level.
297 ##############################
298 # section: private function
299 ##############################
301 ########################################################################
303 ########################################################################
306 # private dbgout function in this lib.
314 # private dbgout function in this lib.
318 if [[ ${SHLIB_DBGOUT_OPT} =~
':shlibinc:' ||
${SHLIB_DBGOUT_OPT} =~
':shlibinc-misc:' ]]; then
324 # private dbgout function in this lib.
328 if [[ ${SHLIB_DBGOUT_OPT} =~
':shlibinc:' ||
${SHLIB_DBGOUT_OPT} =~
':shlibinc-lvlist:' ]]; then
330 printf -v pfx
"%*s" $
(( nest_level
* 4 )) " "
331 echo -ne "${pfx}\033[33m$@\033[0m\n" >&2
336 # private dbgout function in this lib.
340 if [[ ${SHLIB_DBGOUT_OPT} =~
':shlibinc:' ||
${SHLIB_DBGOUT_OPT} =~
':shlibinc-list:' ]]; then
346 # private dbgout function in this lib.
350 if [[ ${SHLIB_DBGOUT_OPT} =~
':shlibinc:' ||
${SHLIB_DBGOUT_OPT} =~
':shlibinc-inc:' ]]; then
355 dbgout_print_elemlist
()
358 local vname
=$
(get_vname_pfx
"$1")
360 tmp_dbgout
"\$1=$1\n"
361 tmp_dbgout
"vname=$vname\n"
363 list2_name
="varlist2_$vname[@]"
364 echo "${list2_name}=${!list2_name}"
365 declare -p varlist2_
$vname
367 list2_name
="funclist2_$vname[@]"
368 echo "${list2_name}=${!list2_name}"
369 declare -p funclist2_
$vname
371 list2_name
="aliaslist2_$vname[@]"
372 echo "${list2_name}=${!list2_name}"
373 declare -p aliaslist2_
$vname
375 list2_name
="ctx_aliaslist2_$vname[@]"
376 echo "${list2_name}=${!list2_name}"
377 declare -p ctx_aliaslist2_
$vname
384 ########################################################################
386 ########################################################################
389 # fsyntax: get_vname_pfx
390 # fdesc: get translate vname string by a function, so that shlib
391 # prefix uses the same syntax by a function.
395 echo "$1" |
sed -E "s|[^[:alnum:]_]|_|g" |
tr '[[:lower:]]' '[[:upper:]]'
399 # vname=${1//[^[:alnum:]_]/_}
403 # nEKfP=${nEKfP%%\.*}
406 # vname="$(basename ${1})"
407 # vname="$(echo $1 | cksum | cut -d ' ' -f1)_${vname//[^_[:alnum:]]/_}"
411 # fsyntax: alias_redefine
412 # fdesc: it re-define an alias cmd for a shlib load in new process.
416 local vname
=$
(get_vname_pfx
"$1")
418 list_dbgout
"######################################################"
419 list_dbgout
"alias_redefine()"
420 dbgout_print_elemlist
"$1"
422 list2_name
="ctx_aliaslist2_$vname"
423 list_dbgout
"${!list2_name}"
427 ########################################################################
428 # list info for var/func/alias
429 ########################################################################
431 # get func list in current process.
442 # get var list in current process.
451 done < <(declare -p |
grep -e "declare" |
sed -e "s/^.*-f.*$//g")
454 # get alias list in current process.
460 # XXX: do not put alias content in list?
462 # data="${data##*alias }"
464 done < <(alias |
grep -e "^alias")
468 # fsyntax: list_diff <type> <name>
469 # outputvarname> = <listvarname1> - <listvarname2>
470 # fdesc: type is one of func/var/alias, name is shlib.
479 list_name
="${1}list1_$vname"
480 list2_name
="${1}list2_$vname"
482 export $list2_name=""
483 # echo "$list2_name define:"
484 # declare -p $list2_name
486 # diff with the list saved before source operation.
490 if [[ "$1" == func
]]; then
491 # add -x option to function, so that sub-proc can use it without load again.
492 declare -f -x ${data}
493 elif [[ "$1" == var
]]; then
494 if [[ "$data" =~
'funclist' ||
"$data" =~
'varlist' ||
"$data" =~
'aliaslist' ]]; then
497 elif [[ "$1" == alias ]]; then
499 data
="${data##*alias }"
502 eval $list2_name+="\"${data} \""
503 done < <(echo "${!list_name}" |
diff --from-file=<(get_
$1_list) - |
grep -e "<")
505 # ctx_xxx, just for alias recovery.
506 [[ "$1" == alias ]] && eval ctx_
$list2_name="\$(alias \${$list2_name})"
509 list_dbgout
"\033[34m==================================\033[0m\n"
510 eval list_dbgout
\"\
${$list2_name[@]}\" |
tr ' ' $
'\n'
511 list_dbgout
"\033[44m==================================\033[0m\n"
515 # fsyntax: get_elem_list null <switchs> <lib-name>
516 # fdesc: get var/func/alias list in current process. it is used for comparing
517 # with the list after shlib load.
521 local vname
=$
(get_vname_pfx
"$3")
523 # when it was a pure include invoking, do not
525 [[ -z $2 ||
"$2" != "load" ]] && return
527 declare -g funclist1_
$vname=""
528 eval funclist1_
$vname=\"\$\
(get_func_list\
)\"
530 declare -g varlist1_
$vname=""
531 eval varlist1_
$vname=\"\$\
(get_var_list\
)\"
533 declare -g aliaslist1_
$vname=""
534 eval aliaslist1_
$vname=\"\$\
(get_alias_list\
)\"
538 # fsyntax: save_lib_elem_list null <switch> <lib-name>
539 # fdesc: get current var/func/alias list again, and comparing with the one saved
540 # in get_curr_elem_list(), output tree array list of var/func/alias, which
541 # is appended by the loaded shlib.
543 save_lib_elem_list
()
545 local vname
=$
(get_vname_pfx
"$3")
547 if [[ "$2" == "load" ]]; then
549 list_diff func
$vname
555 list_diff
alias $vname
560 # xxx_curr_xxx(), it works in nestly sourcing.
561 # it compare list in source file, and update nestly source
566 # fsyntax: get_curr_elem_list <lib-path> <switchs> <lib-name>
567 # fdesc: get var/func/alias list in current process. it is used for comparing
568 # with the list after shlib load.
569 # the difference with get_elem_list() is that it can work in nestly sourcing.
571 get_curr_elem_list
()
573 [[ ! -v nest_level
]] && declare -g nest_level
=""
575 lvlist_dbgout
"get_curr_elem_list ($(basename $1), $2, nest_level=$nest_level)"
577 # save current elem_list for last level
578 if [[ $nest_level != 0 && -n "${nest_level_shlib[$nest_level]}" ]]; then
579 # list_dbgout nest_level=$nest_level
580 lvlist_dbgout
"save_lib_elem_list(null," \
581 "${shlib_load_state[$nest_level]}," \
582 "${nest_level_shlib[$nest_level]}," \
583 "nest_level=$nest_level)\n"
584 # in this fucn, it diff elem list, and append to previous one.
585 save_lib_elem_list null
${shlib_load_state[$nest_level]} "${nest_level_shlib[$nest_level]}"
589 # this code is running in a `` sub-proc.
590 # print ": $((nest_level++))" to update the value in parent process.
591 nest_level
=$
(( nest_level
+ 1 ))
592 nest_level_shlib
[$nest_level]="$3"
593 shlib_load_state
[$nest_level]="$2"
594 loading_flag
[$nest_level]="$inc_flag"
596 # get current elem_list for current level
597 get_elem_list
"$1" "$2" "$3"
598 lvlist_dbgout
"exit get_elem_list($(basename $1), $2, nest_level=$nest_level)"
602 # fsyntax: save_curr_lib_elem_list <lib-path> <switch> <lib-name>
603 # fdesc: get current var/func/alias list again, and comparing with the one saved
604 # in get_curr_elem_list(), output tree array list of var/func/alias, which
605 # is appended by the loaded shlib.
607 save_curr_lib_elem_list
()
611 lvlist_dbgout
"xxx save_curr_lib_elem_list($(basename $1), $2, nest_level=$nest_level)"
613 # release last level elem.
614 unset loading_flag
[$nest_level]
615 unset nest_level_shlib
[$nest_level]
616 unset shlib_load_state
[$nest_level]
618 nest_level
=$
(( nest_level
- 1 ))
619 #nest_level_shlib[$nest_level]="$1"
621 save_lib_elem_list
"$@"
623 if [[ -n "${nest_level_shlib[$nest_level]}" ]]; then
624 get_elem_list
"null" "${shlib_load_state[$nest_level]}" "${nest_level_shlib[$nest_level]}"
625 lvlist_dbgout
"xxx get_elem_list($(basename ${nest_level_shlib[$nest_level]}), $2, nest_level=$nest_level)"
629 save_lib_elem_list_bak
()
631 local vname
=$
(get_vname_pfx
"$3")
636 if [[ "$2" == "load" ]]; then
638 list_name
="funclist1_$vname"
639 list2_name
="funclist2_$vname"
641 declare -g -x $list2_name=""
642 # echo "$list2_name define:"
643 # declare -p $list2_name
644 # diff with the funclist saved before source operation.
646 # add -x option to function, so that sub-proc can use it without load again.
647 declare -f -x ${data##* }
649 eval $list2_name+="\"${data##* } \""
650 done < <(echo "${!list_name}" |
diff --from-file=<(get_func_list
) - |
grep -e "<")
652 list_dbgout
"\033[34m==================================\033[0m\n"
653 list2_name
="${list2_name}[@]"
654 list_dbgout
"${!list2_name}\n"
658 list_name
="varlist1_$vname"
659 list2_name
="varlist2_$vname"
661 declare -g -x $list2_name=""
662 get_var_list
> ~
/b.txt
666 if [[ "$data" =~
'funclist' ||
"$data" =~
'varlist' ||
"$data" =~
'aliaslist' ]]; then
671 # list_dbgout "data=$data\n"
673 eval $list2_name+="\"\${data} \""
674 done < <(echo "${!list_name}" |
diff --from-file=<(get_var_list
) - |
grep -e "<")
676 list_dbgout
"\033[44m==================================\033[0m\n"
677 eval list_dbgout
\"\
${$list2_name[@]}\" |
tr ' ' $
'
682 list_name
="aliaslist1_$vname"
683 list2_name
="aliaslist2_$vname"
685 declare -g -x $list2_name=""
689 data
="${data##*alias }"
690 eval $list2_name+="\"${data} \""
691 done < <(echo "${!list_name}" |
diff --from-file=<(get_alias_list
) - |
grep -e "< alias")
692 ( eval list_dbgout
\"\
${$list2_name}\" ) |
tr ' ' $
'
694 eval $list2_name="\$(alias \${$list2_name})"
696 list_dbgout
"\033[44m==================================\033[0m\n"
697 ( eval list_dbgout
\"\
$list2_name=\
${$list2_name}\" ) |
tr ' ' $
'\n'
698 list_dbgout
"\033[44m==================================\033[0m\n"
702 elemlist_var_clear
()
704 local vname
=$
(get_vname_pfx
"$1")
706 unset varlist2_
$vname
707 unset funclist2_
$vname
708 unset aliaslist2_
$vname
712 # fsyntax: lib_load_prev <lib-path> <inc-type> <lib-name>
713 # fdesc: source lib file, and compare var/func/alias list between before and after of source.
714 # the name of lib must be an absolutly path for shlib file. switch enable the comparing
716 # this function is used for nest inclussion, when some of the variable need to be local
717 # attribute variable.
732 # declare the variable, or it will be defined as a local variable.
733 if [[ $2 == load
]]; then
741 inc_dbgout
"[$2]: XXXXXXXXXXX $1"
742 get_curr_elem_list
$1 $2 $3
743 printf -v pfx
"%*s" $
(( nest_level
* 4 )) " "
744 inc_dbgout
"${pfx}[source]: $1\n"
746 # append variable like 'BASH_SOURCE'
749 tmp
="${tmp//\.shlib}"
751 [[ ! -v SHLIB_IDX ||
-z $SHLIB_IDX ]] && SHLIB_IDX
=0
752 declare -g SHLIB_MODULE_STK
[$SHLIB_IDX]=$SHLIB_MODULE
753 declare -g SHLIB_MODULE
=$
(get_vname_pfx
${tmp^^})
754 declare -g SHLIB_IDX
=$
(( SHLIB_IDX
+ 1 ))
763 declare -g SHLIB_IDX
=$
(( ${SHLIB_IDX} - 1 ))
764 eval declare -g SHLIB_MODULE
=${SHLIB_MODULE_STK[$SHLIB_IDX]}
765 unset SHLIB_MODULE_STK
[$SHLIB_IDX]
767 if [[ $?
== 0 && $ret == 0 ]]; then
770 # misc_dbgout "XXXXXXXXXXXXXXXX $3=${!3}=$1"
771 if [[ $2 == load
]]; then
772 # tmp="$(basename $1)"
775 # tmp=${tmp//[^[:alnum:]_]/_}
780 echo -ne "err: source file($1) failed.\n" >&2
783 save_curr_lib_elem_list
$1 $2 $3
787 # fsyntax: lib_unload_prev <lib-path> <inc-type> <lib-name>
788 # fdesc: source lib file, and compare var/func/alias list between before and after of source.
789 # the name of lib must be an absolutly path for shlib file. switch enable the comparing
791 # this function is used for nest inclussion, when some of the variable need to be local
792 # attribute variable.
796 local vname
=$
(get_vname_pfx
"$3")
801 # release var define.
802 listname
="varlist2_$vname"
805 # release function define.
806 listname
="funclist2_$vname"
809 # release function define.
810 listname
="aliaslist2_$vname"
815 done < <(echo "${!listname}" |
grep -e "^alias ")
820 # fsyntax: lib_path_adapting <xdsource_lib>
826 local xdsource_lib
="$1"
828 if [[ "${xdsource_lib:0:1}" == "/" ]]; then
830 elif [[ "${xdsource_lib:0:2}" == "./" ]]; then
831 xdsource_lib
=$PWD/${xdsource_lib}
833 xdsource_cnt
=${#path_list[@]}
834 for (( xdsource_i
=0; xdsource_i
< xdsource_cnt
; xdsource_i
++ )); do
835 # use eval to change path with '~' char to absolutly path.
836 eval path_list
[$xdsource_i]="${path_list[$xdsource_i]}"
837 if [[ ! -f "${path_list[$xdsource_i]}/$xdsource_lib" ]]; then
840 xdsource_lib
="${path_list[$xdsource_i]}/$xdsource_lib";
844 if [[ $xdsource_i == $xdsource_cnt ]]; then
845 if [[ -f $PWD/$xdsource_lib ]]; then
846 xdsource_lib
="$PWD/$xdsource_lib";
848 echo -ne "err: file $xdsource_lib can not be found in $SHLIB_PATH\n" >&2
860 # fsyntax: uniq_inc_chk <xdsource_lib>
861 # fdesc: inc/load pre-proc for uniq_inc_chk
862 # @ inc_flag, last_inc_flag, tag flag with load/include,
863 # to avoid re-include in nestly sourcing.
864 # @ SHLIB_LIST, SHLIB_INC_LIST, check if current lib has been
865 # loaded or included.
869 local xdsource_lib
="$1"
871 # set this var before lib_load_prev().
872 last_inc_flag
=$inc_flag
873 if [[ $inc_flag == load
]]; then
874 inc_dbgout
"include => load"
880 # uniq include judgement.
881 # SHLIB_LIST is LOADING tag list.
882 # SHLIB_INC_LIST is INCLUDing tag list.
883 if [[ "$SHLIB_INC_LIST" =~
"${xdsource_lib}" ]]; then
884 inc_dbgout
"$xdsource_lib has been included before."
885 inc_dbgout
"SHLIB_INC_LIST=$SHLIB_INC_LIST"
887 if [[ $inc_flag == load
]]; then
888 #conflect with included shlib
889 inc_dbgout
"ignore this conflect in nest include shlib by 'load'."
893 inc_flag
=$last_inc_flag
898 if [[ $inc_flag == load
&& "$SHLIB_LIST" =~
"${xdsource_lib}" ]]; then
899 inc_dbgout
"$xdsource_lib has been loaded before."
900 inc_dbgout
"SHLIB_LIST=$SHLIB_LIST"
902 # just invoke shlib_xxx_init() only in PROG_GVAR_INIT().
903 # xdsource_lib=${xdsource_lib//[^[:alnum:]_]/_}
904 PROG_GVAR_INIT
${xdsource_lib,,}
907 inc_flag
=$last_inc_flag
917 ##############################
918 # section: public function
919 ##############################
921 #alias shlibopt="source shlibopt.sh"
925 source shlibopt.sh $@
930 # 3 type of XXX_PROG_ID_FLAG
931 # @ XXX_PROG_ID_FLAG undefined, it means first time lib loading, invoke init function
932 # in GVAR_INIT, and do nothing in PROG_GVAR_INIT.
933 # @ XXX_PROG_ID_FLAG equal to $$, it means lib has been loaded in current process. do
934 # nothing either in PROG_GVAR_INIT or in GVAR_INIT. return from souce cmd.
935 # @ XXX_PROG_ID_FLAG not equal to $$, it means lib is loaded by session/system process,
936 # and it only need to re-init lib var in one time, but didn't load other functions.
937 # invoke init function in PROG_GVAR_INIT, and return from shlib 'source'(cmd not code),
938 # GVAR_INIT can not be invoked.
940 # there is a example:
941 # stdio.shlib has been loaded by 'include' in sysyem init. program named prog invoke
942 # include stdio.shlib, and shlib_templete.shlib. shlib_templete.shlib invoke include
943 # stdio.shlib. here stdio.shlib is loaded 3 times.
944 # @ first time in system init, and invoke var_init() in GVAR_INIT, while XXX_PROG_ID_FLAG
946 # @ second time in 'prog', XXX_PROG_ID_FLAG is pid of session process, and not equal to
947 # current pid. so invoke var_init() in PROG_GVAR_INIT, and retrun from source cmd.
948 # @ the third time in shlib_templete.shlib, XXX_PROG_ID_FLAG is current pid, and do nothing,
949 # return from source cmd directly.
953 # there are two condition in using. re-include when source include, or invoke in sub-process.
957 # fsyntax: PROG_GVAR_INIT
958 # fdesc: global variable init in shlib, when the lib file has been loaded.
959 # it checks variable setted by GVAR_INIT.
961 alias PROG_GVAR_INIT
='
972 PFX_nEKfP=$(get_vname_pfx "$nEKfP")
976 flag_aFmIG="${PFX_nEKfP}_PROG_ID_FLAG"
977 func_aFmIG="$(declare -F shlib_${nEKfP,,}_init)"
979 if [[ -n ${!flag_aFmIG} && -n "$func_aFmIG" ]]; then
980 if [[ ${!flag_aFmIG} != $$ ]]; then
981 declare -g -x "${flag_aFmIG}=$$"
983 # re-define alias cmd automatically before init.
984 alias_redefine ${input_nEKfP}
987 # it will display error while readonly var is defined
988 # and setted again. odirect stderr to null,
989 # or process by shlib code.
993 inc_dbgout "${nEKfP} re-init.\n"
1007 # fsyntax: GVAR_INIT
1008 # fdesc: set mutex include flag.
1018 PFX_nEKfP=$(get_vname_pfx "$nEKfP")
1022 flag_aFmIG="${PFX_nEKfP}_PROG_ID_FLAG"
1024 if [[ -z ${!flag_aFmIG} ]]; then
1025 declare -g -x "${flag_aFmIG}=$$"
1028 # shlib_${nEKfP}_init
1035 alias PROG_GVAR_CLR
='
1044 PFX_nEKfP=$(get_vname_pfx "$nEKfP")
1048 flag_aFmIG="${PFX_nEKfP}_PROG_ID_FLAG"
1050 unset ${!flag_aFmIG}
1059 # fdesc: the code below let the shlib loading operation only
1060 # executing one time.
1071 PFX_nEKfP=$(get_vname_pfx "$nEKfP")
1075 flag_aFmIG="${PFX_nEKfP}_PROG_ID_FLAG"
1076 func_aFmIG="$(declare -F shlib_${nEKfP,,}_init)"
1078 flag_aFmIG="${PFX_nEKfP}_PROG_ID_FLAG"
1079 func_aFmIG="$(declare -F shlib_${nEKfP,,}_init)"
1080 if [[ -n ${!flag_aFmIG} && -n $func_aFmIG ]]; then
1081 inc_dbgout "uniqlib: return if it has been loaded."
1089 declare -g -x "${flag_aFmIG}=$$"
1098 # this cmd is an alias cmd. if i use source cmd to include
1099 # a shell script file, the global cann't be accessed out
1100 # of function. it seems that variable is defined as local
1101 # variable in function. at first, include cmd defined as
1102 # a script file, and use alias define a wrap cmd like
1103 # 'source dsource '. and then, define include cmd all
1104 # in alias cmd string.
1107 ###########################################################
1108 # TBD: add a switch for en/dis loading when it is included.
1109 ###########################################################
1112 # @ inc => load, load
1113 # @ inc => inc, skip
1114 # @ load => inc, set inc, skip
1115 # @ load => load, skip
1117 # different process:
1118 # @ inc => load, load
1120 # @ load => inc, set inc, skip
1121 # @ load => load, skip
1125 # load operation record different var/func/alias, and set func with -x attr,
1126 # but include operation not.
1127 # include operation declared -x variables could be used in sub-proc. so,
1128 # do not use include in cmdline, it will lead that -x variables does not exist
1129 # in load save list.
1133 # fsyntax: include <lib-name>
1134 # fdesc: include a shlib file unique.
1137 # cannot use stdin as a tty device, the related cmd like stty
1138 # can not work in shlib file. because the stdin is redirected
1141 alias include
=" code='
1146 read -t 1 xdsource_lib
1147 [[ $? != 0 ]] && break
1148 # tmp_dbgout \"xdsource_lib=$xdsource_lib\n\"
1150 path_list=( \$(echo \$SHLIB_PATH | tr \":\" \" \") )
1152 xdsource_name=\$xdsource_lib
1154 uniq_inc_chk \"\$xdsource_lib\" || break
1157 # lib path adapting.
1159 xdsource_lib=\"\$(lib_path_adapting \"\$xdsource_lib\")\"
1161 lib_load_prev \$xdsource_lib \$inc_flag \$xdsource_name
1164 inc_flag=\$last_inc_flag
1178 alias include_bak
=" code='
1185 read -t 1 xdsource_lib
1186 # tmp_dbgout \"xdsource_lib=$xdsource_lib\n\"
1188 xdsource_name=\$xdsource_lib
1190 # set this var before lib_load_prev().
1191 last_inc_flag=\$inc_flag
1192 if [[ \$inc_flag == load ]]; then
1193 inc_dbgout \"include => load\"
1196 inc_flag=\"include\"
1199 path_list=( \$(echo \$SHLIB_PATH | tr \":\" \" \") )
1201 # uniq include judgement.
1202 # SHLIB_LIST is LOADING tag list.
1203 # SHLIB_INC_LIST is INCLUDing tag list.
1204 if [[ \"\$SHLIB_INC_LIST\" =~ \"\${xdsource_lib}\" ]]; then
1205 inc_dbgout \"\$xdsource_lib has been included before.\"
1206 inc_dbgout \"SHLIB_INC_LIST=\$SHLIB_INC_LIST\"
1208 if [[ \$inc_flag == load ]]; then
1209 #conflect with included shlib
1210 inc_dbgout \"ignore this conflect in nest include shlib by 'load'.\"
1214 inc_flag=\$last_inc_flag
1219 if [[ \$inc_flag == load && \"\$SHLIB_LIST\" =~ \"\${xdsource_lib}\" ]]; then
1220 inc_dbgout \"\$xdsource_lib has been loaded before.\"
1221 inc_dbgout \"SHLIB_LIST=\$SHLIB_LIST\"
1223 # just invoke shlib_xxx_init() only in PROG_GVAR_INIT().
1224 # xdsource_lib=\${xdsource_lib//[^[:alnum:]_]/_}
1225 PROG_GVAR_INIT \${xdsource_name,,}
1228 inc_flag=\$last_inc_flag
1235 # lib path adapting.
1237 if [[ \"\${xdsource_lib:0:1}\" == \"/\" ]]; then
1239 elif [[ \"\${xdsource_lib:0:2}\" == \"./\" ]]; then
1240 xdsource_lib=\$PWD/\${xdsource_lib}
1242 xdsource_cnt=\${#path_list[@]}
1243 for (( xdsource_i=0; xdsource_i < xdsource_cnt; xdsource_i++ )); do
1244 # use eval to change path with '~' char to absolutly path.
1245 eval path_list[\$xdsource_i]=\"\${path_list[\$xdsource_i]}\"
1246 if [[ ! -f \"\${path_list[\$xdsource_i]}/\$xdsource_lib\" ]]; then
1249 xdsource_lib=\"\${path_list[\$xdsource_i]}/\$xdsource_lib\";
1253 if [[ \$xdsource_i == \$xdsource_cnt ]]; then
1254 if [[ -f \$PWD/\$xdsource_lib ]]; then
1255 xdsource_lib=\"\$PWD/\$xdsource_lib\";
1257 echo -ne \"err: file \$xdsource_lib can not be found in \$SHLIB_PATH\n\" >&2
1263 lib_load_prev \$xdsource_lib \$inc_flag \$xdsource_name
1266 inc_flag=\$last_inc_flag
1282 # fsyntax: load <lib-name>
1283 # fdesc: load a shlib file uniq in cmdline, it could not be sourced
1284 # by include cmd. when a shlib is very complex, it should be
1285 # load globally to avoid repeated including, to save cpu cost.
1288 # do not invoke 'load' in command line.
1297 read -t 1 xdsource_lib
1299 xdsource_name=\$xdsource_lib
1301 # set this var before lib_load_prev().
1302 last_inc_flag=\$inc_flag
1305 path_list=( \$(echo \$SHLIB_PATH | tr \":\" \" \") )
1307 # SHLIB_LIST is LOADING tag list.
1308 # SHLIB_INC_LIST is INCLUDing tag list.
1309 # deny after include.
1310 if [[ \"\$SHLIB_INC_LIST\" =~ \"\${xdsource_lib}\" ]]; then
1311 inc_dbgout \"\$xdsource_lib has been included before.\"
1312 inc_dbgout \"it can not be loaded!\"
1315 inc_flag=\$last_inc_flag
1320 # uniq include judgement.
1321 if [[ \"\$SHLIB_LIST\" =~ \"\$xdsource_lib\" ]]; then
1322 inc_dbgout \"\$xdsource_lib has been loaded before.\"
1323 inc_dbgout \"execute compact load by invokeding shlib_xxx_init.\"
1324 inc_dbgout \"SHLIB_LIST=\$SHLIB_LIST\"
1327 inc_flag=\$last_inc_flag
1330 # just invoke shlib_xxx_init() only in PROG_GVAR_INIT().
1331 # xdsource_lib=\${xdsource_lib//[^[:alnum:]_]/_}
1332 PROG_GVAR_INIT \${xdsource_name,,}
1336 if [[ \"\${xdsource_lib:0:1}\" == \"/\" ]]; then
1338 elif [[ \"\${xdsource_lib:0:2}\" == \"./\" ]]; then
1339 xdsource_lib=\$PWD/\${xdsource_lib}
1341 xdsource_cnt=\${#path_list[@]}
1342 for (( xdsource_i=0; xdsource_i < xdsource_cnt; xdsource_i++ )); do
1343 # use eval to change path with '~' char to absolutly path.
1344 eval path_list[\$xdsource_i]=\"\${path_list[\$xdsource_i]}\"
1345 if [[ ! -f \"\${path_list[\$xdsource_i]}/\$xdsource_lib\" ]]; then
1348 xdsource_lib=\"\${path_list[\$xdsource_i]}/\$xdsource_lib\";
1352 if [[ \$xdsource_i == \$xdsource_cnt ]]; then
1353 if [[ -f \$PWD/\$xdsource_lib ]]; then
1354 xdsource_lib=\"\$PWD/\$xdsource_lib\";
1356 echo -ne \"err: file \$xdsource_lib can not be found in \$SHLIB_PATH\n\" >&2
1362 lib_load_prev \$xdsource_lib \$inc_flag \$xdsource_name
1365 inc_flag=\$last_inc_flag
1380 alias unload
=" code='
1387 read -t 1 xdsource_lib
1389 xdsource_name=\$xdsource_lib
1391 inc_dbgout \"unload(\$xdsource_name)\n\"
1393 # set this var before lib_unload_prev().
1394 last_inc_flag=\$inc_flag
1397 path_list=( \$(echo \$SHLIB_PATH | tr \":\" \" \") )
1399 # SHLIB_LIST is LOADING tag list.
1400 # SHLIB_INC_LIST is INCLUDing tag list.
1401 # deny after include.
1402 if [[ \"\$SHLIB_INC_LIST\" =~ \"\${xdsource_lib}\" ]]; then
1403 inc_dbgout \"\$xdsource_lib has been included before.\"
1404 inc_dbgout \"it can not be unloaded!\"
1407 inc_flag=\$last_inc_flag
1412 # uniq include judgement.
1413 if [[ ! \"\$SHLIB_LIST\" =~ \"\$xdsource_lib\" ]]; then
1414 inc_dbgout \"\$xdsource_lib has not been loaded before.\"
1415 inc_dbgout \"SHLIB_LIST=\$SHLIB_LIST\"
1418 inc_flag=\$last_inc_flag
1424 inc_dbgout \"\$xdsource_lib has been loaded before.\"
1425 inc_dbgout \"execute compact load by invokeding shlib_xxx_init.\"
1427 # skip file existing judgement.
1429 lib_unload_prev \$xdsource_lib \$inc_flag \$xdsource_name
1430 PROG_GVAR_CLR \$xdsource_name
1431 SHLIB_LIST=\"\$(echo \"\${SHLIB_LIST}\" | grep -v \${xdsource_name})\"
1434 inc_flag=\$last_inc_flag
1450 # fsyntax: reload <lib-name>
1451 # fdesc: load a shlib file uniq in cmdline, it could not be sourced
1452 # by include cmd. when a shlib is very complex, it should be
1453 # load globally to avoid repeated including, to save cpu cost.
1456 # do not invoke 'load' in script code.
1458 alias reload
=" code='
1461 read -t 1 xdsource_xxx
1463 inc_dbgout \"reload(\$xdsource_xxx)\"
1465 unload \$xdsource_xxx
1478 ####################################################################################
1481 # shlib info get and set.
1482 # user can use shlibopt to do this work in command line.
1486 # fsyntax: get_shlib_path
1487 # fdesc: get the path list of shlib.
1491 echo $SHLIB_PATH |
tr ':' '
1496 # fsyntax: get_shlib_path_var <var-name>
1497 # fdesc: get the path list of shlib in a variable.
1499 get_shlib_path_in_var
()
1503 [[ -z $1 ]] && return
1508 eval "${1}=( $SHLIB_PATH )"
1514 # fsyntax: set_shlib_path <PATH>
1515 # fdesc: set the shlib path string.
1519 export SHLIB_PATH
="$1"
1523 path_list
=( $path_list )
1528 # fsyntax: add_shlib_path <PATH>
1529 # fdesc: append a path string to shlib path.
1535 [[ $1 =~ ^\.
/ ]] && path
=$PWD/$1
1537 export SHLIB_PATH
=$
(echo "$SHLIB_PATH:$path" |
tr -s ':')
1541 path_list
+=( $path )
1546 # fsyntax: del_shlib_path <PATH>
1547 # fdesc: delete the N th path string.
1553 # delete path in SHLIB_PATH.
1554 SHLIB_PATH
=$
( echo ${SHLIB_PATH[@]//$1/} |
tr -s $
'\n')
1556 # add eval to expansion operator like '~' to corresponding path.
1557 # so that, $1 use ~ or not does not effect path setting.
1559 SHLIB_PATH
=$
( echo ${SHLIB_PATH[@]//$tmp/} |
tr -s $
'\n')
1564 ####################################################################################
1567 # fsyntax: prev_include <shlibname>
1568 # fdesc: generate shlib file name with path. generate other paramters
1576 local R_LIB_LOAD_LIST
=
1577 local R_LIB_INC_LIST
=
1584 # set this var before lib_load_prev().
1585 last_inc_flag
=$inc_flag
1586 if [[ $inc_flag == load
]]; then
1587 inc_dbgout
"include => load"
1593 path_list
=( $
(echo $SHLIB_PATH |
tr ":" " ") )
1595 # uniq include judgement.
1596 # SHLIB_LIST is LOADING tag list.
1597 # SHLIB_INC_LIST is INCLUDing tag list.
1598 if [[ "$SHLIB_INC_LIST" =~
"${lib}" ]]; then
1599 inc_dbgout
"$lib has been included before."
1600 inc_dbgout
"SHLIB_INC_LIST=$SHLIB_INC_LIST"
1602 if [[ $inc_flag == load
]]; then
1603 #conflect with included shlib
1604 inc_dbgout
"ignore this conflect in nest include shlib by 'load'."
1608 inc_flag
=$last_inc_flag
1613 if [[ $inc_flag == load
&& "$SHLIB_LIST" =~
"${lib}" ]]; then
1614 inc_dbgout
"$lib has been loaded before."
1615 inc_dbgout
"SHLIB_LIST=$SHLIB_LIST"
1617 # just invoke shlib_xxx_init() only in PROG_GVAR_INIT().
1618 # lib=${lib//[^[:alnum:]_]/_}
1619 PROG_GVAR_INIT
${name,,}
1622 inc_flag
=$last_inc_flag
1628 if [[ "${lib:0:1}" == "/" ]]; then
1630 elif [[ "${lib:0:2}" == "./" ]]; then
1633 cnt
=${#path_list[@]}
1634 for (( i
=0; i
< cnt
; i
++ )); do
1635 # use eval to change path with '~' char to absolutly path.
1636 eval path_list
[$i]="${path_list[$i]}"
1637 if [[ ! -f "${path_list[$i]}/$lib" ]]; then
1640 lib
="${path_list[$i]}/$lib";
1644 if [[ $i == $cnt ]]; then
1645 if [[ -f $PWD/$lib ]]; then
1648 echo -ne "err: file $lib can not be found in $SHLIB_PATH\n" >&2
1654 #lib_load_prev $lib $inc_flag $name
1655 echo "$lib $inc_flag $name"
1659 # fsyntax: post_include <param-list> <shlibname>
1665 inc_flag
=$last_inc_flag
1671 # this variable store a function name, which is used to implement features before
1672 # or after source operation.
1674 declare -g shlibwrap_prevcmd
=:
1675 declare -g shlibwrap_postcmd
=:
1682 # read paramter and invoke wrap cmd.
1683 read -t 1 param_BnDfh
1685 file_BnDfh=\"$(eval \$shlibwrap_prevcmd \$param_BnDfh)\"
1686 [[ -z $file_BnDfh ]] && break;
1688 # break invoking in shlib.
1690 source \${file_BnDfh%%\ *}
1694 eval \$shlibwrap_postcmd \$file_BnDfh \$param_BnDfh
1704 # fsyntax: <load-cmd-name> <lib-name>
1705 # fdesc: lib file including cmd string.
1708 # lib name which is used by include cmd, is passed throw stdin redirected by '<<<'.
1709 # but this causes stdin become a pipe, not a tty device. some code invoke 'stty size'
1710 # will return failed, it can not detect stdin as a console.
1712 inc_alias_str
=" { \\\`
1715 read -t 1 xdsource_lib
1717 # [[ -z \\\$path_list ]] && \${INC_NAME}_PATH_LIST=( \\\$(echo \\\$\${INC_NAME}_INC_PATH | tr \\\":\\\" \\\" \\\") )
1719 # include file unique
1720 if [[ \\\"\\\$\${INC_NAME}_INC_LIST\\\" =~ \\\"\\\$xdsource_lib\\\" ]]; then
1724 xdsource_cnt=\\\${#\${INC_NAME}_PATH_LIST[@]}
1725 for (( xdsource_i=0; xdsource_i < xdsource_cnt; xdsource_i++ )); do
1726 if [[ -f \\\${\${INC_NAME}_PATH_LIST[\\\$xdsource_i]}/\\\$xdsource_lib ]]; then
1727 echo \${INC_CMD} \\\\\\\${\${INC_NAME}_PATH_LIST[\\\\\\\$xdsource_i]}/\\\\\\\$xdsource_lib\;
1729 echo [[ \\\\\\\$? == 0 ]] \\&\\& \${INC_NAME}_INC_LIST+=\\\\\\\":\\\\\\\$xdsource_lib\\\\\\\"
1732 # echo source \\\${\${INC_NAME}_PATH_LIST[\\\$xdsource_i]}/\\\$xdsource_lib # && return
1735 [[ \\\$xdsource_i == \\\$xdsource_cnt ]] && echo -ne \\\"err: file \\\$xdsource_lib can not be found in \\\$\${INC_NAME}_INC_PATH\n\${INC_NAME}_INC_PATH=\\\\\\\"\\\$\${INC_NAME}_INC_PATH\\\\\\\"\n\\\" >&2
1742 # fsyntax: <unload-cmd-name> <lib-name>
1743 # fdesc: todo: unload is not implemented.
1745 unload_alias_str
=" { \\\`
1751 # fsyntax: define_include <name> <inc-name> <loadcmd> <unloadcmd> <inc-path>
1752 # fdesc: include feature cmd defination.
1759 for (( i
=$
((${#def_path[@]}-1)); i
>=0; i--
)); do
1760 mkdir
-p "${def_path}"
1763 eval ${name}_INC_PATH
="${5}"
1764 eval ${name}_PATH_LIST
=\
( "$5" \
)
1767 eval alias ${2}="\"$inc_alias_str\""
1772 # fsyntax: define_load <name> <inc-name> <loadcmd> <unloadcmd> <inc-path>
1773 # fdesc: load feature cmd defination.
1780 for (( i
=$
((${#def_path[@]}-1)); i
>=0; i--
)); do
1781 mkdir
-p "${def_path}"
1784 eval ${name}_INC_PATH
="${5}"
1785 eval ${name}_PATH_LIST
=\
( "$5" \
)
1788 eval alias ${2}="\"$inc_alias_str\""
1793 ##############################
1794 # section: file tail
1795 ##############################