2 ############################################################
4 # author: devenkong(18151155@qq.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 # @ debug info output setting by global variable.
35 # @ combine include alias with define_include string.
36 # @ testing for load in different process.
41 # @ global include path.
43 # @ compactly load in sub-script-proc.
44 # @ include files in PWD.
46 # @ if lib in different lib path with same name, they might be mixed.
47 # @ include ./scripts/uniq.shlib
49 # this will record different lib flag in SHLIB_INC_LIST.
50 # maybe use full-path-name will resolve this problem.
53 # @ [shlibinc] binary shlib check and load.
54 # for shlibinc, add a func/alias to check and load binary shlib.
55 # at the beginning of shlib src file, add a binary lib checking cmd. if the
56 # shlib implemented by a binary lib, load it first, and do not load script code
61 # SHLIB_VERSION, shlib version infomation.
62 # include <shlib-file>, used to include a shlib in the process of current program.
63 # it will be uniq included in a process. once include, does not need to
64 # be 'source' again. but it still need to be included in a new sub-script
66 # load/unload <shlib-file>, used to load a shlib in system, or current session,
67 # or current process. the difference with include is that, it recode the
68 # global var & func & alias cmd in exported env var, and set them with
69 # export attribute. when the shlib would be load in a new script program,
70 # it still keep load content.
71 # reload <shlib-file>, used to load a shlib again if shlib is updated.
72 # PROG_GVAR_INIT <libname>, global variable init in shlib, when the lib file
74 # GVAR_INIT <libname>, global variable first init in shlib.
75 # uniqlib <libname>, skip loading the code after this cmd, if the shlib has
77 # get_shlib_path, print shlib one path string by one line.
78 # get_shlib_path_var <var-name>, get the shlib path in var array.
79 # set_shlib_path <PATH>, set whole shlib path string.
80 # add_shlib_path <PATH>, append path to shlib path.
81 # del_shlib_path <PATH>, delete path by specified string.
82 # define_include <> <> <> <>, define a include cmd for a kind of lib file.
86 # enable alias feature in script.
87 shopt -s expand_aliases
89 # init ROOTFS if it is not /
90 if [[ ! -d $ROOTFS ]]; then
91 TMP_DIR
=`dirname $(which ls)`/..
92 TMP_DIR
=`cd $TMP_DIR; pwd; cd - > /dev/null`
93 ROOTFS
=${ROOTFS:-$TMP_DIR}
98 # save current process id every time when this file is sourced in a program.
103 # shlib module name stack.
105 if [[ ! -v SHLIB_IDX ||
-z $SHLIB_IDX ]]; then
106 declare -g SHLIB_IDX
=0
107 declare -g SHLIB_MODULE
=${BASH_SOURCE[1]##*\/}
108 SHLIB_MODULE
=${SHLIB_MODULE^^}
113 ##############################
114 # section: public comment info
115 ##############################
118 #echo SHLIB_VERSION=$SHLIB_VERSION
120 ##############################
121 # section: variable define
122 ##############################
125 # todo: comment this code, exported function cannot be use in sub-process.
128 # unique executing judged by shlib version variable.
129 #if [[ -n $SHLIB_VERSION ]]; then
131 # invoke global var init if this script file is invoked in a shlib
133 # [[ -n $1 ]] && PROG_GVAR_INIT $1
135 # echo shlibinc has been loaded, skip to save cpu cost.
138 # shlibinc only could be used by source
139 # use return to exit from current script file.
147 # if defined as exported var, it can be used for feature of one time code loading.
148 # but this feature can not works.
151 SHLIB_VERSION
="0.0.1"
154 # it stored shlib paths like enviroument variable 'PATH'.
156 SHLIB_PATH
=${SHLIB_PATH:-`echo $ROOTFS/usr/shlib:$ROOTFS/usr/libexec/dvar/shlib`}
160 # an array of SHLIB_PATH path.
161 if [[ -z $path_list ]]; then
164 path_list
=( $SHLIB_PATH )
169 # @ include时,判断SHLIB_LIST,已include,skip。首次include中,调用_init()函数,设置SHLIB_LIST。
171 # # 判断SHLIB_INC_LIST,已load,且判断SHLIB_LIST中未load,只调用_init()进行初始化+ 判断SHLIB_INC_LIST,已load,且判断SHLIB_LIST中已load,skip
172 # # 其它,首次load时,调用_init()函数,设置SHLIB_INC_LIST和当前进程的SHLIB_LIST。SHLIB_LIST在创建新进程时不export。
176 # fsyntax: decl_shlib_var <var-name>
177 # fdesc: check exist before var declare, and add SHLIB__ prefix.
181 [[ ! -v SHLIB__
${1^^} ]] && declare -g SHLIB__
${1^^}
186 # LIST variable have not been used
188 if [[ ! -v SHLIB_INC_LIST
]]; then
189 declare -g SHLIB_INC_LIST
=${SHLIB_INC_LIST=""}
191 if [[ ! -v SHLIB_LIST
]]; then
192 declare -g -x SHLIB_LIST
=${SHLIB_LIST=""}
194 #SHLIB_LIST=${SHLIB_LIST=""}
197 [[ ! -v nest_level
]] && declare -g nest_level
=0
199 [[ ! -v nest_level_shlib
]] && declare -g -a nest_level_shlib
[0]=""
202 [[ ! -v shlib_load_state
]] && declare -g -a shlib_load_state
[0]=0
204 # do not append -x attr, it should be resetted in sub-process.
205 [[ ! -v loading_flag
]] && declare -g -a loading_flag
[0]=0
207 # TBD: this var should be used as a load type for shlib,
208 # code in shlib use it to set different variable type, -x or not.
209 [[ ! -v inc_flag
]] && declare -g -a inc_flag
=""
210 [[ ! -v last_inc_flag
]] && declare -g last_inc_flag
=""
213 ##############################
214 # section: private function
215 ##############################
218 # private dbgout function in this lib.
226 # private dbgout function in this lib.
230 if [[ ${SHLIB_DBGOUT_OPT} =~
':shlibinc:' ||
${SHLIB_DBGOUT_OPT} =~
':shlibinc-misc:' ]]; then
236 # private dbgout function in this lib.
240 if [[ ${SHLIB_DBGOUT_OPT} =~
':shlibinc:' ||
${SHLIB_DBGOUT_OPT} =~
':shlibinc-list:' ]]; then
246 # private dbgout function in this lib.
250 if [[ ${SHLIB_DBGOUT_OPT} =~
':shlibinc:' ||
${SHLIB_DBGOUT_OPT} =~
':shlibinc-inc:' ]]; then
256 # fsyntax: get_vname_pfx
257 # fdesc: get translate vname string by a function, so that the shlib
258 # prefix uses the same syntax by a function.
264 vname
=${1//[^[:alnum:]_]/_}
267 # nEKfP=${nEKfP%%\.*}
270 # vname="$(basename ${1})"
271 # vname="$(echo $1 | cksum | cut -d ' ' -f1)_${vname//[^_[:alnum:]]/_}"
275 # fsyntax: alias_redefine
276 # fdesc: it re-define an alias cmd for a shlib load in new process.
280 local vname
=$
(get_vname_pfx
"$1")
282 list_dbgout
"######################################################"
283 list_dbgout
"alias_redefine()"
284 dbgout_print_elemlist
"$1"
286 list2_name
="aliaslist2_$vname"
287 list_dbgout
"${!list2_name}"
291 # get func list in current process.
302 # get var list in current process.
311 done < <(declare -p |
grep -e "declare" |
sed -e "s/^.*-f.*$//g")
312 # declare -F | grep -E "declare" | sed -e "s/^.*-f.*$//g"
315 # get alias list in current process.
322 done < <(alias |
grep -e "^alias")
326 # fsyntax: get_elem_list null <switchs> <lib-name>
327 # fdesc: get var/func/alias list in current process. it is used for comparing
328 # with the list after shlib load.
332 local vname
=$
(get_vname_pfx
"$3")
334 # when it was a pure include invoking, do not
336 [[ -z $2 ||
"$2" != "load" ]] && return
338 declare -g funclist1_
$vname=""
339 eval funclist1_
$vname=\"\$\
(get_func_list\
)\"
341 declare -g varlist1_
$vname=""
342 eval varlist1_
$vname=\"\$\
(get_var_list\
)\"
344 declare -g aliaslist1_
$vname=""
345 eval aliaslist1_
$vname=\"\$\
(get_alias_list\
)\"
349 # fsyntax: get_curr_elem_list <lib-name> <switchs>
350 # fdesc: get var/func/alias list in current process. it is used for comparing
351 # with the list after shlib load.
353 get_curr_elem_list
()
362 [[ ! -v nest_level
]] && declare -g nest_level
=""
364 printf -v pfx
"%*s" $
(( nest_level
* 4 )) " "
365 list_dbgout
"${pfx}get_curr_elem_list ($(basename $1), $2, nest_level=$nest_level)"
367 # save current elem_list for last level
368 if [[ $nest_level != 0 && -n "${nest_level_shlib[$nest_level]}" ]]; then
369 # list_dbgout nest_level=$nest_level
370 printf -v pfx
"%*s" $
(( nest_level
* 4 )) " "
371 list_dbgout
"${pfx}\033[33msave_lib_elem_list(null, ${shlib_load_state[$nest_level]}, ${nest_level_shlib[$nest_level]}, nest_level=$nest_level)\033[0m\n"
372 save_lib_elem_list null
${shlib_load_state[$nest_level]} "${nest_level_shlib[$nest_level]}"
376 # this code is running in a `` sub-proc.
377 # print ": $((nest_level++))" to update the value in parent process.
378 nest_level
=$
(( nest_level
+ 1 ))
379 nest_level_shlib
[$nest_level]="$3"
380 shlib_load_state
[$nest_level]="$2"
381 loading_flag
[$nest_level]="$inc_flag"
383 # get current elem_list for current level
384 get_elem_list
"$1" "$2" "$3"
385 printf -v pfx
"%*s" $
(( nest_level
* 4 )) " "
386 list_dbgout
"${pfx}\033[0mxxx get_elem_list($(basename $1), $2, nest_level=$nest_level)\033[0m"
390 # fsyntax: save_curr_lib_elem_list <lib-path> <switch> <lib-name>
391 # fdesc: get current var/func/alias list again, and comparing with the one saved
392 # in get_curr_elem_list(), output tree array list of var/func/alias, which
393 # is appended by the loaded shlib.
395 save_curr_lib_elem_list
()
399 printf -v pfx
"%*s" $
(( nest_level
* 4 )) " "
400 list_dbgout
"${pfx}\033[0mxxx save_curr_lib_elem_list($(basename $1), $2, nest_level=$nest_level)\033[0m"
402 # release last level elem.
403 unset loading_flag
[$nest_level]
404 unset nest_level_shlib
[$nest_level]
405 unset shlib_load_state
[$nest_level]
407 nest_level
=$
(( nest_level
- 1 ))
408 #nest_level_shlib[$nest_level]="$1"
410 save_lib_elem_list
"$@"
412 if [[ -n "${nest_level_shlib[$nest_level]}" ]]; then
413 get_elem_list
"null" "${shlib_load_state[$nest_level]}" "${nest_level_shlib[$nest_level]}"
414 printf -v pfx
"%*s" $
(( nest_level
* 4 )) " "
415 list_dbgout
"${pfx}\033[0mxxx get_elem_list($(basename ${nest_level_shlib[$nest_level]}), $2, nest_level=$nest_level)\033[0m"
419 dbgout_print_elemlist
()
422 local vname
=$
(get_vname_pfx
"$1")
424 tmp_dbgout
"\$1=$1\n"
425 tmp_dbgout
"vname=$vname\n"
427 list2_name
="varlist2_$vname[@]"
428 echo "${list2_name}=${!list2_name}"
429 declare -p varlist2_
$vname
431 list2_name
="funclist2_$vname[@]"
432 echo "${list2_name}=${!list2_name}"
433 declare -p funclist2_
$vname
435 list2_name
="aliaslist2_$vname[@]"
436 echo "${list2_name}=${!list2_name}"
437 declare -p aliaslist2_
$vname
443 # fsyntax: save_lib_elem_list null <switch> <lib-name>
444 # fdesc: get current var/func/alias list again, and comparing with the one saved
445 # in get_curr_elem_list(), output tree array list of var/func/alias, which
446 # is appended by the loaded shlib.
448 save_lib_elem_list
()
450 local vname
=$
(get_vname_pfx
"$3")
455 if [[ "$2" == "load" ]]; then
457 list_name
="funclist1_$vname"
458 list2_name
="funclist2_$vname"
460 declare -g -x $list2_name=""
461 # echo "$list2_name define:"
462 # declare -p $list2_name
463 # diff with the funclist saved before source operation.
465 # add -x option to function, so that sub-proc can use it without load again.
466 declare -f -x ${data##* }
468 eval $list2_name+="\"${data##* } \""
469 done < <(echo "${!list_name}" |
diff --from-file=<(get_func_list
) - |
grep -e "<")
471 list_dbgout
"\033[34m==================================\033[0m\n"
472 list2_name
="${list2_name}[@]"
473 list_dbgout
"${!list2_name}\n"
477 list_name
="varlist1_$vname"
478 list2_name
="varlist2_$vname"
480 declare -g -x $list2_name=""
481 get_var_list
> ~
/b.txt
485 if [[ "$data" =~
'funclist' ||
"$data" =~
'varlist' ||
"$data" =~
'aliaslist' ]]; then
490 # list_dbgout "data=$data\n"
492 eval $list2_name+="\"\${data} \""
493 done < <(echo "${!list_name}" |
diff --from-file=<(get_var_list
) - |
grep -e "<")
495 list_dbgout
"\033[44m==================================\033[0m\n"
496 eval list_dbgout
\"\
${$list2_name[@]}\" |
tr ' ' $
'
501 list_name
="aliaslist1_$vname"
502 list2_name
="aliaslist2_$vname"
504 declare -g -x $list2_name=""
508 data
="${data##*alias }"
509 eval $list2_name+="\"${data} \""
510 done < <(echo "${!list_name}" |
diff --from-file=<(get_alias_list
) - |
grep -e "< alias")
511 ( eval list_dbgout
\"\
${$list2_name}\" ) |
tr ' ' $
'
513 eval $list2_name="\$(alias \${$list2_name})"
515 list_dbgout
"\033[44m==================================\033[0m\n"
516 ( eval list_dbgout
\"\
$list2_name=\
${$list2_name}\" ) |
tr ' ' $
'\n'
517 list_dbgout
"\033[44m==================================\033[0m\n"
521 elemlist_var_clear
()
523 local vname
=$
(get_vname_pfx
"$1")
525 unset varlist2_
$vname
526 unset funclist2_
$vname
527 unset aliaslist2_
$vname
531 # fsyntax: lib_load_prev <lib-path> <inc-type> <lib-name>
532 # fdesc: source lib file, and compare var/func/alias list between before and after of source.
533 # the name of lib must be an absolutly path for shlib file. switch enable the comparing
535 # this function is used for nest inclussion, when some of the variable need to be local
536 # attribute variable.
549 if [[ $2 == load
]]; then
555 # declare the variable, or it will be defined as a local variable.
559 inc_dbgout
"[$2]: XXXXXXXXXXX $1"
560 get_curr_elem_list
$1 $2 $3
561 printf -v pfx
"%*s" $
(( nest_level
* 4 )) " "
562 inc_dbgout
"${pfx}[source]: $1\n"
564 # append variable like 'BASH_SOURCE'
567 tmp
="${tmp//\.shlib}"
569 [[ ! -v SHLIB_IDX ||
-z $SHLIB_IDX ]] && SHLIB_IDX
=0
570 declare -g SHLIB_MODULE_STK
[$SHLIB_IDX]=$SHLIB_MODULE
571 declare -g SHLIB_MODULE
=$
(get_vname_pfx
${tmp^^})
572 declare -g SHLIB_IDX
=$
(( SHLIB_IDX
+ 1 ))
581 declare -g SHLIB_IDX
=$
(( ${SHLIB_IDX} - 1 ))
582 eval declare -g SHLIB_MODULE
=${SHLIB_MODULE_STK[$SHLIB_IDX]}
583 unset SHLIB_MODULE_STK
[$SHLIB_IDX]
585 if [[ $?
== 0 ]]; then
588 # misc_dbgout "XXXXXXXXXXXXXXXX $3=${!3}=$1"
589 if [[ $2 == load
]]; then
590 # tmp="$(basename $1)"
593 # tmp=${tmp//[^[:alnum:]_]/_}
598 echo -ne "err: source file($1) failed.\n" >&2
601 save_curr_lib_elem_list
$1 $2 $3
605 # fsyntax: unlib_load_prev <lib-path> <inc-type> <lib-name>
606 # fdesc: source lib file, and compare var/func/alias list between before and after of source.
607 # the name of lib must be an absolutly path for shlib file. switch enable the comparing
609 # this function is used for nest inclussion, when some of the variable need to be local
610 # attribute variable.
614 local vname
=$
(get_vname_pfx
"$3")
619 # release var define.
620 listname
="varlist2_$vname"
623 # release function define.
624 listname
="funclist2_$vname"
627 # release function define.
628 listname
="aliaslist2_$vname"
633 done < <(echo "${!listname}" |
grep -e "^alias ")
638 ##############################
639 # section: public function
640 ##############################
642 #alias shlibopt="source shlibopt.sh"
646 source shlibopt.sh $@
651 # 3 type of XXX_PROG_ID_FLAG
652 # @ XXX_PROG_ID_FLAG undefined, it means first time lib loading, invoke init function
653 # in GVAR_INIT, and do nothing in PROG_GVAR_INIT.
654 # @ XXX_PROG_ID_FLAG equal to $$, it means lib has been loaded in current process. do
655 # nothing either in PROG_GVAR_INIT or in GVAR_INIT. return from souce cmd.
656 # @ XXX_PROG_ID_FLAG not equal to $$, it means lib is loaded by session/system process,
657 # and it only need to re-init lib var in one time, but didn't load other functions.
658 # invoke init function in PROG_GVAR_INIT, and return from shlib 'source'(cmd not code),
659 # GVAR_INIT can not be invoked.
661 # there is a example:
662 # stdio.shlib has been loaded by 'include' in sysyem init. program named prog invoke
663 # include stdio.shlib, and shlib_templete.shlib. shlib_templete.shlib invoke include
664 # stdio.shlib. here stdio.shlib is loaded 3 times.
665 # @ first time in system init, and invoke var_init() in GVAR_INIT, while XXX_PROG_ID_FLAG
667 # @ second time in 'prog', XXX_PROG_ID_FLAG is pid of session process, and not equal to
668 # current pid. so invoke var_init() in PROG_GVAR_INIT, and retrun from source cmd.
669 # @ the third time in shlib_templete.shlib, XXX_PROG_ID_FLAG is current pid, and do nothing,
670 # return from source cmd directly.
674 # there are two condition in using. re-include when source include, or invoke in sub-process.
678 # fsyntax: PROG_GVAR_INIT
679 # fdesc: global variable init in shlib, when the lib file has been loaded.
680 # it checks variable setted by GVAR_INIT.
682 alias PROG_GVAR_INIT
='
693 PFX_nEKfP=$(get_vname_pfx "$nEKfP")
697 flag_aFmIG="${PFX_nEKfP}_PROG_ID_FLAG"
698 func_aFmIG="$(declare -F shlib_${nEKfP,,}_init)"
700 if [[ -n ${!flag_aFmIG} && -n "$func_aFmIG" ]]; then
701 if [[ ${!flag_aFmIG} != $$ ]]; then
702 declare -g -x "${flag_aFmIG}=$$"
704 # re-define alias cmd automatically before init.
705 alias_redefine ${input_nEKfP}
708 # it will display error while readonly var is defined
709 # and setted again. odirect stderr to null,
710 # or process by shlib code.
714 inc_dbgout "${nEKfP} re-init.\n"
729 # fdesc: set mutex include flag.
739 PFX_nEKfP=$(get_vname_pfx "$nEKfP")
743 flag_aFmIG="${PFX_nEKfP}_PROG_ID_FLAG"
745 if [[ -z ${!flag_aFmIG} ]]; then
746 declare -g -x "${flag_aFmIG}=$$"
749 # shlib_${nEKfP}_init
756 alias PROG_GVAR_CLR
='
765 PFX_nEKfP=$(get_vname_pfx "$nEKfP")
769 flag_aFmIG="${PFX_nEKfP}_PROG_ID_FLAG"
780 # fdesc: the code below let the shlib loading operation only
781 # executing one time.
792 PFX_nEKfP=$(get_vname_pfx "$nEKfP")
796 flag_aFmIG="${PFX_nEKfP}_PROG_ID_FLAG"
797 func_aFmIG="$(declare -F shlib_${nEKfP,,}_init)"
799 flag_aFmIG="${PFX_nEKfP}_PROG_ID_FLAG"
800 func_aFmIG="$(declare -F shlib_${nEKfP,,}_init)"
801 if [[ -n ${!flag_aFmIG} && -n $func_aFmIG ]]; then
802 inc_dbgout "uniqlib: return if it has been loaded."
810 declare -g -x "${flag_aFmIG}=$$"
819 # this cmd is an alias cmd. if i use source cmd to include
820 # a shell script file, the global cann't be accessed out
821 # of function. it seems that variable is defined as local
822 # variable in function. at first, include cmd defined as
823 # a script file, and use alias define a wrap cmd like
824 # 'source dsource '. and then, define include cmd all
825 # in alias cmd string.
828 ###########################################################
829 # TBD: add a switch for en/dis loading when it is included.
830 ###########################################################
833 # @ inc => load, load
835 # @ load => inc, set inc, skip
836 # @ load => load, skip
839 # @ inc => load, load
841 # @ load => inc, set inc, skip
842 # @ load => load, skip
846 # load operation record different var/func/alias, and set func with -x attr,
847 # but include operation not.
848 # include operation declared -x variables could be used in sub-proc. so,
849 # do not use include in cmdline, it will lead that -x variables does not exist
854 # fsyntax: include <lib-name>
855 # fdesc: include a shlib file unique.
858 # cannot use stdin as a tty device, the related cmd like stty
859 # can not work in shlib file. because the stdin is redirected
862 alias include
=" code='
869 read -t 1 xdsource_lib
870 # tmp_dbgout \"xdsource_lib=$xdsource_lib\n\"
872 xdsource_name=\$xdsource_lib
874 # set this var before lib_load_prev().
875 last_inc_flag=\$inc_flag
876 if [[ \$inc_flag == load ]]; then
877 inc_dbgout \"include => load\"
883 path_list=( \$(echo \$SHLIB_PATH | tr \":\" \" \") )
885 # uniq include judgement.
886 # SHLIB_LIST is LOADING tag list.
887 # SHLIB_INC_LIST is INCLUDing tag list.
888 if [[ \"\$SHLIB_INC_LIST\" =~ \"\${xdsource_lib}\" ]]; then
889 inc_dbgout \"\$xdsource_lib has been included before.\"
890 inc_dbgout \"SHLIB_INC_LIST=\$SHLIB_INC_LIST\"
892 if [[ \$inc_flag == load ]]; then
893 #conflect with included shlib
894 inc_dbgout \"ignore this conflect in nest include shlib by 'load'.\"
898 inc_flag=\$last_inc_flag
903 if [[ \$inc_flag == load && \"\$SHLIB_LIST\" =~ \"\${xdsource_lib}\" ]]; then
904 inc_dbgout \"\$xdsource_lib has been loaded before.\"
905 inc_dbgout \"SHLIB_LIST=\$SHLIB_LIST\"
907 # just invoke shlib_xxx_init() only in PROG_GVAR_INIT().
908 # xdsource_lib=\${xdsource_lib//[^[:alnum:]_]/_}
909 PROG_GVAR_INIT \${xdsource_name,,}
912 inc_flag=\$last_inc_flag
918 if [[ \"\${xdsource_lib:0:1}\" == \"/\" ]]; then
920 elif [[ \"\${xdsource_lib:0:2}\" == \"./\" ]]; then
921 xdsource_lib=\$PWD/\${xdsource_lib}
923 xdsource_cnt=\${#path_list[@]}
924 for (( xdsource_i=0; xdsource_i < xdsource_cnt; xdsource_i++ )); do
925 # use eval to change path with '~' char to absolutly path.
926 eval path_list[\$xdsource_i]=\"\${path_list[\$xdsource_i]}\"
927 if [[ ! -f \"\${path_list[\$xdsource_i]}/\$xdsource_lib\" ]]; then
930 xdsource_lib=\"\${path_list[\$xdsource_i]}/\$xdsource_lib\";
934 if [[ \$xdsource_i == \$xdsource_cnt ]]; then
935 if [[ -f \$PWD/\$xdsource_lib ]]; then
936 xdsource_lib=\"\$PWD/\$xdsource_lib\";
938 echo -ne \"err: file \$xdsource_lib can not be found in \$SHLIB_PATH\n\" >&2
944 lib_load_prev \$xdsource_lib \$inc_flag \$xdsource_name
947 inc_flag=\$last_inc_flag
963 # fsyntax: load <lib-name>
964 # fdesc: load a shlib file uniq in cmdline, it could not be sourced
965 # by include cmd. when a shlib is very complex, it should be
966 # load globally to avoid repeated including, to save cpu cost.
969 # do not invoke 'load' in command line.
978 read -t 1 xdsource_lib
980 xdsource_name=\$xdsource_lib
982 # set this var before lib_load_prev().
983 last_inc_flag=\$inc_flag
986 path_list=( \$(echo \$SHLIB_PATH | tr \":\" \" \") )
988 # SHLIB_LIST is LOADING tag list.
989 # SHLIB_INC_LIST is INCLUDing tag list.
990 # deny after include.
991 if [[ \"\$SHLIB_INC_LIST\" =~ \"\${xdsource_lib}\" ]]; then
992 inc_dbgout \"\$xdsource_lib has been included before.\"
993 inc_dbgout \"it can not be loaded!\"
996 inc_flag=\$last_inc_flag
1001 # uniq include judgement.
1002 if [[ \"\$SHLIB_LIST\" =~ \"\$xdsource_lib\" ]]; then
1003 inc_dbgout \"\$xdsource_lib has been loaded before.\"
1004 inc_dbgout \"execute compact load by invokeding shlib_xxx_init.\"
1005 inc_dbgout \"SHLIB_LIST=\$SHLIB_LIST\"
1008 inc_flag=\$last_inc_flag
1011 # just invoke shlib_xxx_init() only in PROG_GVAR_INIT().
1012 # xdsource_lib=\${xdsource_lib//[^[:alnum:]_]/_}
1013 PROG_GVAR_INIT \${xdsource_name,,}
1017 if [[ \"\${xdsource_lib:0:1}\" == \"/\" ]]; then
1019 elif [[ \"\${xdsource_lib:0:2}\" == \"./\" ]]; then
1020 xdsource_lib=\$PWD/\${xdsource_lib}
1022 xdsource_cnt=\${#path_list[@]}
1023 for (( xdsource_i=0; xdsource_i < xdsource_cnt; xdsource_i++ )); do
1024 # use eval to change path with '~' char to absolutly path.
1025 eval path_list[\$xdsource_i]=\"\${path_list[\$xdsource_i]}\"
1026 if [[ ! -f \"\${path_list[\$xdsource_i]}/\$xdsource_lib\" ]]; then
1029 xdsource_lib=\"\${path_list[\$xdsource_i]}/\$xdsource_lib\";
1033 if [[ \$xdsource_i == \$xdsource_cnt ]]; then
1034 if [[ -f \$PWD/\$xdsource_lib ]]; then
1035 xdsource_lib=\"\$PWD/\$xdsource_lib\";
1037 echo -ne \"err: file \$xdsource_lib can not be found in \$SHLIB_PATH\n\" >&2
1043 lib_load_prev \$xdsource_lib \$inc_flag \$xdsource_name
1046 inc_flag=\$last_inc_flag
1061 alias unload
=" code='
1068 read -t 1 xdsource_lib
1070 xdsource_name=\$xdsource_lib
1072 inc_dbgout \"unload(\$xdsource_name)\n\"
1074 # set this var before unlib_load_prev().
1075 last_inc_flag=\$inc_flag
1078 path_list=( \$(echo \$SHLIB_PATH | tr \":\" \" \") )
1080 # SHLIB_LIST is LOADING tag list.
1081 # SHLIB_INC_LIST is INCLUDing tag list.
1082 # deny after include.
1083 if [[ \"\$SHLIB_INC_LIST\" =~ \"\${xdsource_lib}\" ]]; then
1084 inc_dbgout \"\$xdsource_lib has been included before.\"
1085 inc_dbgout \"it can not be unloaded!\"
1088 inc_flag=\$last_inc_flag
1093 # uniq include judgement.
1094 if [[ ! \"\$SHLIB_LIST\" =~ \"\$xdsource_lib\" ]]; then
1095 inc_dbgout \"\$xdsource_lib has not been loaded before.\"
1096 inc_dbgout \"SHLIB_LIST=\$SHLIB_LIST\"
1099 inc_flag=\$last_inc_flag
1105 inc_dbgout \"\$xdsource_lib has been loaded before.\"
1106 inc_dbgout \"execute compact load by invokeding shlib_xxx_init.\"
1108 # skip file existing judgement.
1110 unlib_load_prev \$xdsource_lib \$inc_flag \$xdsource_name
1111 PROG_GVAR_CLR \$xdsource_name
1112 SHLIB_LIST=\"\$(echo \"\${SHLIB_LIST}\" | grep -v \${xdsource_name})\"
1115 inc_flag=\$last_inc_flag
1131 # fsyntax: reload <lib-name>
1132 # fdesc: load a shlib file uniq in cmdline, it could not be sourced
1133 # by include cmd. when a shlib is very complex, it should be
1134 # load globally to avoid repeated including, to save cpu cost.
1137 # do not invoke 'load' in script code.
1139 alias reload
=" code='
1142 read -t 1 xdsource_xxx
1144 inc_dbgout \"reload(\$xdsource_xxx)\"
1146 unload \$xdsource_xxx
1159 ####################################################################################
1162 # shlib info get and set.
1163 # user can use shlibopt to do this work in command line.
1167 # fsyntax: get_shlib_path
1168 # fdesc: get the path list of shlib.
1172 echo $SHLIB_PATH |
tr ':' '
1177 # fsyntax: get_shlib_path_var <var-name>
1178 # fdesc: get the path list of shlib in a variable.
1180 get_shlib_path_in_var
()
1184 [[ -z $1 ]] && return
1189 eval "${1}=( $SHLIB_PATH )"
1195 # fsyntax: set_shlib_path <PATH>
1196 # fdesc: set the shlib path string.
1200 export SHLIB_PATH
="$1"
1204 path_list
=( $path_list )
1209 # fsyntax: add_shlib_path <PATH>
1210 # fdesc: append a path string to shlib path.
1216 [[ $1 =~ ^\.
/ ]] && path
=$PWD/$1
1218 export SHLIB_PATH
=$
(echo "$SHLIB_PATH:$path" |
tr -s ':')
1222 path_list
+=( $path )
1227 # fsyntax: del_shlib_path <PATH>
1228 # fdesc: delete the N th path string.
1234 # delete path in SHLIB_PATH.
1235 SHLIB_PATH
=$
( echo ${SHLIB_PATH[@]//$1/} |
tr -s $
'\n')
1237 # add eval to expansion operator like '~' to corresponding path.
1238 # so that, $1 use ~ or not does not effect path setting.
1240 SHLIB_PATH
=$
( echo ${SHLIB_PATH[@]//$tmp/} |
tr -s $
'\n')
1245 ####################################################################################
1248 # fsyntax: prev_include <shlibname>
1249 # fdesc: generate shlib file name with path. generate other paramters
1257 local R_LIB_LOAD_LIST
=
1258 local R_LIB_INC_LIST
=
1265 # set this var before lib_load_prev().
1266 last_inc_flag
=$inc_flag
1267 if [[ $inc_flag == load
]]; then
1268 inc_dbgout
"include => load"
1274 path_list
=( $
(echo $SHLIB_PATH |
tr ":" " ") )
1276 # uniq include judgement.
1277 # SHLIB_LIST is LOADING tag list.
1278 # SHLIB_INC_LIST is INCLUDing tag list.
1279 if [[ "$SHLIB_INC_LIST" =~
"${lib}" ]]; then
1280 inc_dbgout
"$lib has been included before."
1281 inc_dbgout
"SHLIB_INC_LIST=$SHLIB_INC_LIST"
1283 if [[ $inc_flag == load
]]; then
1284 #conflect with included shlib
1285 inc_dbgout
"ignore this conflect in nest include shlib by 'load'."
1289 inc_flag
=$last_inc_flag
1294 if [[ $inc_flag == load
&& "$SHLIB_LIST" =~
"${lib}" ]]; then
1295 inc_dbgout
"$lib has been loaded before."
1296 inc_dbgout
"SHLIB_LIST=$SHLIB_LIST"
1298 # just invoke shlib_xxx_init() only in PROG_GVAR_INIT().
1299 # lib=${lib//[^[:alnum:]_]/_}
1300 PROG_GVAR_INIT
${name,,}
1303 inc_flag
=$last_inc_flag
1309 if [[ "${lib:0:1}" == "/" ]]; then
1311 elif [[ "${lib:0:2}" == "./" ]]; then
1314 cnt
=${#path_list[@]}
1315 for (( i
=0; i
< cnt
; i
++ )); do
1316 # use eval to change path with '~' char to absolutly path.
1317 eval path_list
[$i]="${path_list[$i]}"
1318 if [[ ! -f "${path_list[$i]}/$lib" ]]; then
1321 lib
="${path_list[$i]}/$lib";
1325 if [[ $i == $cnt ]]; then
1326 if [[ -f $PWD/$lib ]]; then
1329 echo -ne "err: file $lib can not be found in $SHLIB_PATH\n" >&2
1335 #lib_load_prev $lib $inc_flag $name
1336 echo "$lib $inc_flag $name"
1340 # fsyntax: post_include <param-list> <shlibname>
1346 inc_flag
=$last_inc_flag
1352 # this variable store a function name, which is used to implement features before
1353 # or after source operation.
1355 declare -g shlibwrap_prevcmd
=:
1356 declare -g shlibwrap_postcmd
=:
1363 # read paramter and invoke wrap cmd.
1364 read -t 1 param_BnDfh
1366 file_BnDfh=\"$(eval \$shlibwrap_prevcmd \$param_BnDfh)\"
1367 [[ -z $file_BnDfh ]] && break;
1369 # break invoking in shlib.
1371 source \${file_BnDfh%%\ *}
1375 eval \$shlibwrap_postcmd \$file_BnDfh \$param_BnDfh
1385 # fsyntax: <load-cmd-name> <lib-name>
1386 # fdesc: lib file including cmd string.
1389 # lib name which is used by include cmd, is passed throw stdin redirected by '<<<'.
1390 # but this causes stdin become a pipe, not a tty device. some code invoke 'stty size'
1391 # will return failed, it can not detect stdin as a console.
1393 inc_alias_str
=" { \\\`
1396 read -t 1 xdsource_lib
1398 # [[ -z \\\$path_list ]] && \${INC_NAME}_PATH_LIST=( \\\$(echo \\\$\${INC_NAME}_INC_PATH | tr \\\":\\\" \\\" \\\") )
1400 # include file unique
1401 if [[ \\\"\\\$\${INC_NAME}_INC_LIST\\\" =~ \\\"\\\$xdsource_lib\\\" ]]; then
1405 xdsource_cnt=\\\${#\${INC_NAME}_PATH_LIST[@]}
1406 for (( xdsource_i=0; xdsource_i < xdsource_cnt; xdsource_i++ )); do
1407 if [[ -f \\\${\${INC_NAME}_PATH_LIST[\\\$xdsource_i]}/\\\$xdsource_lib ]]; then
1408 echo \${INC_CMD} \\\\\\\${\${INC_NAME}_PATH_LIST[\\\\\\\$xdsource_i]}/\\\\\\\$xdsource_lib\;
1410 echo [[ \\\\\\\$? == 0 ]] \\&\\& \${INC_NAME}_INC_LIST+=\\\\\\\":\\\\\\\$xdsource_lib\\\\\\\"
1413 # echo source \\\${\${INC_NAME}_PATH_LIST[\\\$xdsource_i]}/\\\$xdsource_lib # && return
1416 [[ \\\$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
1423 # fsyntax: <unload-cmd-name> <lib-name>
1424 # fdesc: todo: unload is not implemented.
1426 unload_alias_str
=" { \\\`
1432 # fsyntax: define_include <name> <inc-name> <loadcmd> <unloadcmd> <inc-path>
1433 # fdesc: include feature cmd defination.
1440 for (( i
=$
((${#def_path[@]}-1)); i
>=0; i--
)); do
1441 mkdir
-p "${def_path}"
1444 eval ${name}_INC_PATH
="${5}"
1445 eval ${name}_PATH_LIST
=\
( "$5" \
)
1448 eval alias ${2}="\"$inc_alias_str\""
1453 # fsyntax: define_load <name> <inc-name> <loadcmd> <unloadcmd> <inc-path>
1454 # fdesc: load feature cmd defination.
1461 for (( i
=$
((${#def_path[@]}-1)); i
>=0; i--
)); do
1462 mkdir
-p "${def_path}"
1465 eval ${name}_INC_PATH
="${5}"
1466 eval ${name}_PATH_LIST
=\
( "$5" \
)
1469 eval alias ${2}="\"$inc_alias_str\""
1474 ##############################
1475 # section: file tail
1476 ##############################
1482 alias include_bak
=" { \` while true; do
1485 read -t 1 xdsource_lib
1487 misc_dbgout nest_level=$nest_level
1489 # [[ -z \$path_list ]] &&
1490 path_list=( \$(echo \$SHLIB_PATH | tr \":\" \" \") )
1492 #echo \"path_list=${path_list[@]}/\\\$xdsource_lib\" >&2
1494 if [[ \"\$SHLIB_INC_LIST\" =~ \"\$xdsource_lib\" ]]; then
1495 echo \"\$xdsource_lib has been included before.\" >&2
1498 echo \"[\$xdsource_lib].\" >&2
1502 xdsource_cnt=\${#path_list[@]}
1503 for (( xdsource_i=0; xdsource_i < xdsource_cnt; xdsource_i++ )); do
1504 if [[ -f \"\${path_list[\$xdsource_i]}/\$xdsource_lib\" ]]; then
1505 #echo \"echo [inc] \$xdsource_lib;\"
1506 echo \"get_curr_elem_list \$xdsource_lib; echo ret=\\\\\\$?;\"
1507 echo \"echo \\\"aa \\\$? PID=\\\$\\\$ nest_level=\$nest_level\\\";\"
1508 echo source \\\${path_list[\\\$xdsource_i]}/\\\$xdsource_lib\;
1509 echo \"save_curr_lib_elem_list \$xdsource_lib 1;\"
1510 # echo \"path_list=\\\${path_list[\\\$xdsource_i]}/\\\$xdsource_lib\" >&2
1512 echo [[ \\\$? == 0 ]] \&\& SHLIB_INC_LIST+=\\\":\\\$xdsource_lib\\\"
1515 # echo source \${path_list[\$xdsource_i]}/\$xdsource_lib # && return
1518 if [[ \$xdsource_i == \$xdsource_cnt ]]; then
1519 if [[ \\\$PWD/\\\$xdsource_lib ]]; then
1520 #echo \"echo \\\"[inc] \$xdsource_lib\\\\\\n;\\\"\"
1521 echo \"eval get_curr_elem_list \$xdsource_lib;\"
1522 echo \"echo \\\"aa \\\$? PID=\\\$\\\$ nest_level=\$nest_level\\\";\"
1523 echo \"source \\\$PWD/\\\$xdsource_lib;\"
1524 echo \"save_curr_lib_elem_list \$xdsource_lib 1;\"
1525 echo [[ \\\$? == 0 ]] \&\& SHLIB_INC_LIST+=\\\":\\\$xdsource_lib\\\"
1527 echo -ne \"err: file \$xdsource_lib can not be found in \$SHLIB_PATH\n\$SHLIB_PATH=\\\"\$SHLIB_PATH\\\"\n\" >&2
1537 misc_dbgout z nest_level=\$nest_level;
1538 nest_level=$((nest_level+1))
1539 misc_dbgout z nest_level=\$nest_level;
1542 alias unload_bak
=" { \` while true; do
1547 read -t 1 xdsource_lib
1549 # [[ -z \$path_list ]] &&
1550 path_list=( \$(echo \$SHLIB_PATH | tr \":\" \" \") )
1552 #echo \"path_list=${path_list[@]}/\\\$xdsource_lib\" >&2
1554 if [[ \"\$SHLIB_LIST\" =~ \"\$xdsource_lib\" ]]; then
1555 echo \"\$xdsource_lib has been included before.\" >&2
1558 echo \"[\$xdsource_lib].\" >&2
1562 xdsource_cnt=\${#xdsource_fun[@]}
1563 for (( xdsource_i=0; xdsource_i < xdsource_cnt; xdsource_i++ )); do
1565 if [[ -f \"\${xdsource_fun[\$xdsource_i]}/\$xdsource_lib\" ]]; then
1566 #echo \"echo [inc] \$xdsource_lib;\"
1567 echo \"get_curr_elem_list \$xdsource_lib; echo ret=\\\\\\$?;\"
1568 echo source \\\${xdsource_fun[\\\$xdsource_i]}/\\\$xdsource_lib\;
1569 echo \"save_curr_lib_elem_list \$xdsource_lib 1;\"
1570 # echo \"xdsource_fun=\\\${xdsource_fun[\\\$xdsource_i]}/\\\$xdsource_lib\" >&2
1572 echo [[ \\\$? == 0 ]] \&\& SHLIB_LIST+=\\\":\\\$xdsource_lib\\\"
1575 # echo source \${xdsource_fun[\$xdsource_i]}/\$xdsource_lib # && return
1578 if [[ \$xdsource_i == \$xdsource_cnt ]]; then
1579 if [[ \\\$PWD/\\\$xdsource_lib ]]; then
1580 #echo \"echo \\\"[inc] \$xdsource_lib\\\\\\n;\\\"\"
1581 echo \"eval get_curr_elem_list \$xdsource_lib;\"
1582 echo \"source \\\$PWD/\\\$xdsource_lib;\"
1583 echo \"save_curr_lib_elem_list \$xdsource_lib 1;\"
1584 echo [[ \\\$? == 0 ]] \&\& SHLIB_LIST+=\\\":\\\$xdsource_lib\\\"
1586 echo -ne \"err: file \$xdsource_lib can not be found in \$SHLIB_PATH\n\$SHLIB_PATH=\\\"\$SHLIB_PATH\\\"\n\" >&2
1598 # reload shlib when code is updated.
1600 alias reloadshlib_bak
=" { \` while true; do
1603 read -t 1 xdsource_lib
1605 # [[ -z \$path_list ]] &&
1606 path_list=( \$(echo \$SHLIB_PATH | tr \":\" \" \") )
1608 #echo \"path_list=${path_list[@]}/\\\$xdsource_lib\" >&2
1611 xdsource_cnt=\${#path_list[@]}
1612 for (( xdsource_i=0; xdsource_i < xdsource_cnt; xdsource_i++ )); do
1613 if [[ -f \${path_list[\$xdsource_i]}/\$xdsource_lib ]]; then
1614 echo source \\\${path_list[\\\$xdsource_i]}/\\\$xdsource_lib\;
1615 # echo \"path_list=\\\${path_list[\\\$xdsource_i]}/\\\$xdsource_lib\" >&2
1617 echo [[ \\\$? == 0 ]] \&\& SHLIB_LIST+=\\\":\\\$xdsource_lib\\\"
1620 # echo source \${path_list[\$xdsource_i]}/\$xdsource_lib # && return
1623 [[ \$xdsource_i == \$xdsource_cnt ]] && echo -ne \"err: file \$xdsource_lib can not be found in \$SHLIB_PATH\n\$SHLIB_PATH=\\\"\$SHLIB_PATH\\\"\n\" >&2
1633 # those code below, is reserved for shlib unload
1637 # fsyntax: uniqlib [<lib-name>]
1638 # fdesc: it used in shlib to let the code load unique, and others will be
1639 # running every time.
1643 [[ -n \`eval eval echo \\\\\\\${__SHLIB_\\\$(basename \${BASH_SOURCE//./_})__}\` ]] && echo \"included 2nd .\" && return
1644 declare -g __SHLIB_\`basename \${BASH_SOURCE//./_}\`__=1
1645 eval ENV_SHLIB_\`basename \${BASH_SOURCE//./_}\`=\\\"\$(env)\\\"
1646 eval \"ALIAS_SHLIB_\`basename \${BASH_SOURCE//./_}\`=( \\\"\${!BASH_ALIASES[@]}\\\" )\"
1647 eval FUNC_SHLIB_\`basename \${BASH_SOURCE//./_}\`=\\\"\$(declare -F)\\\"
1653 # fdesc: use with uniqlib at the end of uniq-block.
1656 # declare -g __SHLIB_\`basename \${BASH_SOURCE//./_}\`_TMP__=1
1657 eval ENV_SHLIB_\`basename \${BASH_SOURCE//./_}\`_TMP=\\\"\$(env)\\\"
1658 declare -g ALIAS_SHLIB_\`basename \${BASH_SOURCE//./_}\`_TMP=( \"\${!BASH_ALIASES[@]}\" )
1659 eval FUNC_SHLIB_\`basename \${BASH_SOURCE//./_}\`_TMP=\\\"\$(declare -F)\\\"
1661 #eval ENV_SHLIB_\`basename \${BASH_SOURCE//./_}\`=get_var_txt_appended ENV_SHLIB_\`basename \${BASH_SOURCE//./_}\` ENV_SHLIB_\`basename \${BASH_SOURCE//./_}\`_TMP
1662 eval echo list=\\\"\\\${ENV_SHLIB_\`basename \${BASH_SOURCE//./_}\`}\\\"