2 ############################################################
3 # source: catalog.shlib
4 # author: CottonCandyOwner(CottonCandyOwner@126.com)
6 ############################################################
8 # catalog is a file that orgnize text string like tree-struct
9 # by tabs. it is a good describe file for program design draft.
10 # maybe it is used for program module struct describe, or for
11 # rootfs dir struct describe, for menu structure. use
12 # catalog.shlib to despatch file, and do some thing automatically.
13 # catalog contain a catalog-id, id=A.B.C. it can be used
14 # to describe range of catalog operating, or exlude some id,
15 # when the program ergodic a catalog file.
16 # every catalog is consisted by describe line string.
17 # different syntax can be used for different purpose. this
18 # shlib defined some syntax used for some application. eg:
19 # scripttest, codegen.
21 ############################################################
26 # @ catalog file content is consiste of two part, one is dir and file, the
27 # other is file content structure. they are dispatched and restored in
28 # different variable category.
29 # @ sub-catalog. if a catalog file referenced in another catalog item, it
30 # will add prefix for the referenced catalog.
34 # @ 在<>中,-之后可根据需要添加一个6个字符的随机字符串,用于和<<<>>>中的cataid进行匹配。
35 # 使用固定cataid时,可不用随机字符串。在cataidreset成<->时,对content中的catanode的<<<>>>添加随机字符串,并保存到cataid的关联数组。当变量dir时,对应cataid使用相关随机字符串。
47 ##############################
48 # section: public comment info
49 ##############################
53 ##############################
54 # section: variable define
55 ##############################
59 vonCataNodeProc
=onDefaultCataNodeProc
63 vonItemSubjectDirEntering
=
67 vonDirSubjectDirEntering
=
73 # global temp var used in strfmt
78 #NCATAID_REGEX="([[:xdigit:]-]*)"
80 NNAME_REGEX
="([[:alnum:]_]*)"
81 #NDESC_REGEX="([[:alnum:]_-+[:blank:]]*)"
82 NDESC_REGEX
="([^\.\"]*)"
83 NODE_TYPE_REGEX
="([[:alnum:]_]*)"
84 ALIGN_REGEX
='([[:blank:]]+)'
86 # replace tab with blank string.
101 # current ITEM info for content proc
125 ##############################
126 # section: private function
127 ##############################
132 ##############################
133 # section: public function
134 ##############################
139 ###########################################################################
141 ###########################################################################
146 # catalog_id/NFULLCATAID
152 # fsyntax: save_curr_ctx <name>
153 # fdesc: save current contex to specified name prefix.
154 # current contex include NFULLCATAID LAYEDDIR_*
160 if [[ -z $name ]]; then
162 BAK_LASTTABS
=$LASTTABS
165 LAST_ID_NUM_BAK
=( "${LAST_ID_NUM[@]}" )
166 LAST_DIR_TABS_BAK_TESTDIR
="$LAST_DIR_TABS_SRCDIR"
167 LAST_DIR_TABS_BAK_DOCDIR
="$LAST_DIR_TABS_DOCDIR"
168 LAST_DIR_TABS_BAK_DESIGNDIR
="$LAST_DIR_TABS_DESIGNDIR"
169 LAST_DIR_TABS_BAK_TESTDIR
="$LAST_DIR_TABS_TESTDIR"
172 BAK_CONTEX
[$name]="$(eval declare -p $CTX_BAK_VAR_LIST)"
173 BAK_CONTEX
[$name]="${BAK_CONTEX[$name]//declare/declare -g}"
181 if [[ -z $name ]]; then
183 LASTTABS
=$BAK_LASTTABS
186 CATACNT
=$
((TABS
- LASTTABS
))
190 LAST_ID_NUM
=( "${LAST_ID_NUM_BAK[@]}" )
191 LAST_DIR_TABS
="$LAST_DIR_TABS_BAK"
192 LAST_DIR_TABS_SRCDIR
="$LAST_DIR_TABS_BAK_TESTDIR"
193 LAST_DIR_TABS_DOCDIR
="$LAST_DIR_TABS_BAK_DOCDIR"
194 LAST_DIR_TABS_DESIGNDIR
="$LAST_DIR_TABS_BAK_DESIGNDIR"
195 LAST_DIR_TABS_TESTDIR
="$LAST_DIR_TABS_BAK_TESTDIR"
196 unset LAST_ID_NUM_BAK
${!LAST_DIR_TABS_BAK_*}
201 [[ -z "${BAK_CONTEX[$name]}" ]] && echo "BAK_CONTEX[$name] does not setted."
202 eval "${BAK_CONTEX[$name]}"
204 if [[ $name != BAK
]]; then
205 REF_ITEM_CATAID
="$NFULLCATAID"
206 # declare -p TEST_CID TEST_DIR_DEPTH NFULLCATAID
207 cataid_set TEST
$NFULLCATAID
212 # fsyntax: del_bak_ctx <name>
218 [[ -z $name ]] && name
=BAK
219 unset BAK_CONTEX
[$name]
225 if [[ -n $LASTTABS ]]; then
226 CATACNT
=$
((TABS-LASTTABS
))
231 ITEM_CHKSUM
="$(echo "$NTYPE $NNAME $NDESC" | cksum)"
232 ITEM_CHKSUM
="${ITEM_CHKSUM:0:6}"
234 # item reference by ITEM_CHKSUM
235 if [[ "${NCATAID:0:2}" == '<<' && "${NCATAID: -2:2}" == '>>' ]]; then
237 # <<<>>> is an item reference, it entering contex specified in <<<>>>.
238 # save current contex first, then set to contex specified in <<<>>>.
239 # restore current contex in func of onItemExiting().
241 dbgoutd
"#############################################\n"
243 [[ -z "${BAK_CONTEX[$ITEM_CHKSUM]}" ]] && warn
"BAK_CONTEX[$ITEM_CHKSUM] does not defined.\n" && return
245 # save current contex
249 restore_curr_ctx
"$ITEM_CHKSUM"
251 # declare -p NCATAID NFULLCATAID ${!ITEM_LAYEDDIR_*}
252 NCATAID
="${NFULLCATAID##*\.}"
253 # declare -p NFULLCATAID NCATAID TEST_DIR_DEPTH TEST_CID BAK_CID BAK_DIR_DEPTH
258 if [[ $REF_ITEM_STATE == 1 ]]; then
262 if [[ "$CATACNT" -gt 0 ]]; then
263 if [[ "${NCATAID}" == '-' ]]; then
264 NCATAID
="${CATAID_BEGIN_VAL}"
267 for ((; CATACNT
>1; CATACNT--
)); do
268 cataid_step_into_id TEST
$CATAID_BEGIN_VAL
271 cataid_step_into_id TEST
$NCATAID
272 elif [[ "$CATACNT" -lt 0 ]]; then
273 tmp
="$((0 - CATACNT))"
274 for ((; tmp
>0; tmp--
)); do
275 unset LAST_ID_NUM
[$TEST_DIR_DEPTH]
279 if [[ "${NCATAID}" == '-' ]]; then
280 NCATAID
="${TEST_CID[$TEST_DIR_DEPTH]}"
281 LAST_ID_NUM
[$TEST_DIR_DEPTH]=$NCATAID
282 NCATAID
="$((NCATAID+1))"
285 cataid_step_to TEST
$NCATAID
287 if [[ "${NCATAID}" == '-' ]]; then
288 NCATAID
=$
((LAST_ID_NUM
[$TEST_DIR_DEPTH]+1))
291 cataid_step_to TEST
$NCATAID
293 NFULLCATAID
="$(cataid_get TEST)"
294 # declare -p NFULLCATAID TEST_DIR_DEPTH TEST_CID
296 LAST_ID_NUM
[$TEST_DIR_DEPTH]=$NCATAID
298 # declare -p CATACNT TEST_DIR_DEPTH LAST_ID_NUM NCATAID NFULLCATAID
302 # fsyntax: catalog_each_line <catafile>
303 # design file analyzing.
304 # @ 1.get each line data
305 # @ 2.calc indent level
306 # @ 3.disposing node string to NXXX variables
307 # @ 4.get type info indent
308 # @ 5.relative info process
314 local tabcnt
= # blank count equals to a tab.
315 local tabstr
= # a string equals to a tab.
318 # declare -p G_NODE_STR_FMT G_NODE_PAIRCHARS
321 # 1.get each line data
322 # get line data by readln, but not 'read'.
323 # it improve blank char getting at the beginning of line string.
325 while readln data
; do
326 [[ $verbose == "enable" ]] && info
"data=$data\n"
327 [[ ${data//[ \t]/} =~ ^
[[:blank
:]]*\
# ]] && continue
329 [[ -z ${data} ]] && continue
330 if [[ $data == 'exit' ]]; then
331 $vonItemExiting "$ITEM_NODE_TYPE" "$ITEM_LAYEDDIR_TESTDIR" "$ITEM_DIR_NAME_TESTDIR"
333 [[ -n $THISDOC ]] && $vonThisDoc
335 elif [[ $data =~ ^ignore
]]; then
336 local cnt
="${data#*\ }"
338 for ((i
=0; i
<$cnt; i
++)); do
342 #[[ -n $THISDOC ]] && $vonThisDoc
345 elif [[ $data =~ ^print
]]; then
346 local var
="${data#*\ }"
349 if [[ ! "$data" =~ ^
[[:blank
:]]*[[:punct
:]|
[:digit
:]] ]]; then
350 THISDOC
+="$(echo "${data}" | sed -e 's/^[[:blank:]]*//g')"$
'\n'
352 elif [[ -z ${data//[[:blank:]]/} ]]; then
356 [[ -n $THISDOC ]] && $vonThisDoc
357 if [[ -n $THISDOC ]]; then
362 if [[ "${data: -1:1}" == '\' ]]; then
364 # here use read not readln, it will skip blanks at the beginning of
366 # -r will ignore '\' special-char.
367 while read -d $
'\n' -r tmp
; do
368 if [[ "${tmp: -1:1}" == '\' ]]; then
378 # 2.calc indent level
379 # get tab and blank count as catalog indent level number.
381 LASTBLANKCNT=${BLANKCNT}
383 BLANKCNT=${data%%[^[:blank:]]*}
384 data="${data#$BLANKCNT}"
385 BLANKCNT="${BLANKCNT//\t/$tabstr}"
386 eval "BLANKCNT=\"\${BLANKCNT//$'\t'/$TAB_BLANK_STR}\""
387 BLANKCNT="${#BLANKCNT}"
388 LASTBLANKCNT=${LASTBLANKCNT:-"$BLANKCNT"}
390 # value in the first line to be the size unit in current file.
391 [[ -z $tabcnt ]] && tabcnt=$BLANKCNT && tabstr="`printf "%*s" $((TABS*tabcnt)) " "`"
392 [[ $tabcnt == 0 ]] && tabcnt=4 && tabstr="`printf "%*s" $((TABS*4)) " "`"
393 TABS=$(( BLANKCNT/${tabcnt:-'4'} ))
395 # declare -p LASTBLANKCNT BLANKCNT TABS LASTTABS tabcnt tabstr
398 # 3.disposing node string to NXXX variables
400 STR_FMT="$G_NODE_STR_FMT"
401 PAIRCHARS="$G_NODE_PAIRCHARS"
403 # declare -p STR_FMT PAIRCHARS
406 if [[ -z $NCATAID || -z $NNAME || -z $NTYPE || -z $NDESC ]]; then
407 err "node string '$data' can not matching variables.\n"
411 # echo ======================================
412 # declare -p NCATAID NTYPE NNAME NDESC # STR_FMT ALIGN
413 # echo ======================================
417 # NTYPE => SRC_TYPE & NODE_TYPE(dir/item/cont)
420 if [[ "$NTYPE" =~ dir$ ]]; then
421 [[ "$NTYPE" == 'ignrdir
' ]] && return 1
425 # <NULL>/src/lib/bin/shlib/ex
426 if [[ "$NTYPE" != 'dir
' ]]; then
427 SRC_TYPE="${NTYPE%dir}"
429 if [[ $TABS != 1 && -n $SRC_TYPE ]]; then
430 warn "(NTYPE=$NTYPE, TABS=$TABS, SRC_TYPE=$SRC_TYPE)do not specify dir type not in first dir level."
433 elif [[ "$CONT_TYPE_LIST" =~ $NTYPE ]]; then
436 elif [[ "$NTYPE" =~ ^cont- ]]; then
437 dbgoutd "\$NTYPE =~ ^cont-"
438 # keep SRC_TYPE processed before.
440 CONT_TYPE="${NTYPE#cont-}"
442 # keep SRC_TYPE processed before.
447 # echo ++++++++++++++++++++++++++++++++++++++++++++++
448 # declare -p SRC_TYPE NODE_TYPE ITEM_TYPE 2>/dev/null
449 # echo ++++++++++++++++++++++++++++++++++++++++++++++
451 if [[ ${NODE_TYPE} != 'cont
' &&
452 -n $ITEM_NFULLCATAID &&
453 $ITEM_NFULLCATAID != NFULLCATAID ]]; then
454 if [[ -n $REF_ITEM_CATAID && -n "${BAK_CONTEX[BAK]}" ]]; then
455 # ${#NFULLCATAID} -le ${#REF_ITEM_CATAID} &&
456 # ${NFULLCATAID} != ${REF_ITEM_CATAID} ]]; then
463 # 5.indent relative info process
464 # NCATAID, maybe it is a string with <<>> or '-'.
465 # NFULLCATAID, generated by cataid_xxx().
466 # CATACNT, TABS change count,
467 # >0 entering into a sub-node,
468 # <0 exiting from a sub-node,
469 # =0 same sub-node dir,
472 # declare -p NFULLCATAID CATACNT
473 # echo ======================================
475 [[ -n $var ]] && declare -p $var
479 # analyze string to node variable.
483 LAST_TYPE="${NODE_TYPE}"
488 # XXX: does not used now.
493 # output dir under srcpkg.
499 # get info from $NCATAID $NTYPE $NNAME $NDESC
501 onDefaultCataNodeProc ()
511 #if [[ ${NODE_TYPE} != 'cont
' && ${LAST_TYPE} == 'cont
' ]]; then
512 if [[ ${NODE_TYPE} != 'cont
' &&
513 -n $ITEM_NFULLCATAID &&
514 $ITEM_NFULLCATAID != NFULLCATAID ]]; then
515 $vonItemExiting "$ITEM_NODE_TYPE" "$ITEM_LAYEDDIR_TESTDIR" "$ITEM_DIR_NAME_TESTDIR"
516 ITEM_NCATAID="" ITEM_NTYPE="" ITEM_NNAME="" ITEM_NDESC=""
518 ITEM_NODE_TYPE="" ITEM_DIR_NAME="" ITEM_LAYEDDIR=""
519 unset ${!ITEM_LAYEDDIR_*} ${!ITEM_DIR_NAME_*}
523 if [[ "$NODE_TYPE" == 'dir
' ]]; then
524 NFTYPE="$(envar_get catalog::${NODE_TYPE}node::NFTYPE)"
525 # | sed -e "s/\;([[:blank:]])*([\n])*/\n/g"
526 elif [[ "$NODE_TYPE" == 'item
' ]]; then
527 NFTYPE="$(envar_get catalog::${ITEM_TYPE}::NFTYPE)"
528 $vonItemEntering "$NFULLCATAID" "$ITEM_CHKSUM" "$NNAME"
529 elif [[ "$NODE_TYPE" == 'cont
' ]]; then
530 $vonContProc "$CONT_TYPE" "$NNAME" "$NDESC"
534 NFTYPE="${NFTYPE//\;/$'\n'}"
535 # TBD: the statement below does not effect in script, but it can work
537 #NFTYPE="${NFTYPE//\;*([[:blank:]])*($'\n')/$'\n'}"
539 # NFTYPE => DIR_DESC => DIR_TYPE_LIST & FILE_EXT_LIST
541 # DIR_TYPE_LIST => DIR_TYPE
542 # DIR_TYPE => OUTPUT_DIR_FMT
543 # DIR_TYPE + catalog::${DIR_TYPE}::STR_FMT => DIR_NAME
544 # DIR_TYPE => LAYEDDIR_${DIR_TYPE^^}[@] => OUTPUT_DIR
546 # FILE_EXT_LIST => NFEXT => <one-of-item-file-name>
548 [[ -z ${data//[[:blank:]]/} ]] && continue
550 DIR_DESC="${data%%:*}"
551 DIR_DESC="${DIR_DESC//\//$'\n'}"
556 if [[ -n $tmp ]]; then
559 FILE_EXT_LIST=( $tmp )
563 for DIR_TYPE in ${DIR_DESC}; do
564 DIR_TYPE_LIST="${DIR_TYPE}"$'\n'
566 [[ ${DIR_TYPE:0:1} == '@
' ]] && new_dir_flags=1 && DIR_TYPE="${DIR_TYPE:1}"
570 # if it is an item node, it is used for sub-dir name when
571 # new_dir_flags tagged.
573 STR_FMT="$(envar_get catalog::${DIR_TYPE}::STR_FMT)"
580 if [[ ${NODE_TYPE} == 'dir
' && $new_dir_flags == 1 ]]; then
581 tmp="LAST_DIR_TABS_${DIR_TYPE^^}"
582 if [[ -n ${!tmp} ]]; then
583 tmp="$((TABS - ${!tmp}))"
587 # declare -p LAST_DIR_TABS_${DIR_TYPE^^} tmp TABS
588 if [[ "$tmp" -lt 0 ]]; then
589 tmpcnt="$((0 - tmp))"
590 eval tmp="\${#LAYEDDIR_${DIR_TYPE^^}[@]}"
591 if [[ -n $tmp && $tmp -gt 0 ]]; then
592 for ((idx=0; idx<=tmpcnt; idx++)); do
593 local tmpidx=$((tmp - idx - 1))
595 # declare -p tmp idx tmpcnt tmpidx
596 if [[ $tmpidx -ge 0 ]]; then
597 unset LAYEDDIR_${DIR_TYPE^^}[$tmpidx]
599 warn "indent is not correct."
602 # declare -p DIR_NAME LAYEDDIR_${DIR_TYPE^^}
603 tmp=$((tmp - tmpcnt - 1))
604 [[ $tmp -ge 0 ]] && eval LAYEDDIR_${DIR_TYPE^^}[$tmp]=\"\$DIR_NAME\"
606 elif [[ "$tmp" == 0 ]]; then
607 eval tmp="\${#LAYEDDIR_${DIR_TYPE^^}[@]}"
609 if [[ $tmp -ge 0 ]]; then
610 eval LAYEDDIR_${DIR_TYPE^^}[$tmp]=\"\$DIR_NAME\"
612 eval "LAYEDDIR_${DIR_TYPE^^}=( \"\$DIR_NAME\" )"
614 elif [[ "$tmp" == 1 ]]; then
615 eval "LAYEDDIR_${DIR_TYPE^^}+=( \"\$DIR_NAME\" )"
617 err "TABS=$TABS LASTTABS=$LASTTABS LAST_DIR_TABS=$LAST_DIR_TABS tmp=$tmp dir node define err.\n"
620 eval LAST_DIR_TABS_${DIR_TYPE^^}="$TABS"
622 # save to ITEM_* info
623 eval ITEM_LAYEDDIR_${DIR_TYPE^^}=\( "\"\${LAYEDDIR_${DIR_TYPE^^}[@]}\"" \)
626 # declare -p LAYEDDIR_${DIR_TYPE^^}
628 eval LAYEDDIR="\${LAYEDDIR_${DIR_TYPE^^}[@]}"
629 LAYEDDIR="${LAYEDDIR//\ /\/}"
630 # declare -p LAYEDDIR LAYEDDIR_${DIR_TYPE^^} 2>/dev/null
632 if [[ -n $LAYEDDIR ]]; then
635 NPFXID="${NFULLCATAID}"
638 SUBJECTDIR="$(envar_get catalog::${DIR_TYPE}::SUBJECTDIR)"
639 OUTPUT_DIR_FMT="$(envar_get catalog::${DIR_TYPE}::OUTPUT_DIR_FMT)"
640 [[ -z $OUTPUT_DIR_FMT ]] && OUTPUT_DIR_FMT="$G_OUTPUT_DIR_FMT"
641 strfmt @OUTPUT_DIR_FMT
642 # declare -p G_OUTPUT_DIR_FMT OUTPUT_DIR_FMT OUTPUT_DIR SUBJECTDIR
644 mkdir -p "$OUTPUT_DIR"
646 # declare -p new_dir_flags DIR_TYPE NPFXID SUBJECTDIR STR_FMT
647 # declare -p DIR_NAME FILE_EXT_LIST OUTPUT_DIR_FMT LAYEDDIR_${DIR_TYPE^^} LAYEDDIR
649 if [[ ${NODE_TYPE} == 'item
' && $new_dir_flags == 1 ]]; then
652 ITEMNODE_DIR="DIR_NAME"
656 # 2.file output proc.
658 if [[ ${NODE_TYPE} == 'dir
' ]]; then
659 $vonDirSubjectDirEntering "${DIR_TYPE}" "${SUBJECTDIR}" "${DIR_NAME}"
661 for NFEXT in ${FILE_EXT_LIST[@]}; do
662 STR_FMT="$(envar_get catalog::${NFEXT}::STR_FMT)"
664 FILE_NAME_LIST[$DIR_TYPE]+="touch ${OUTPUT_DIR}/$ITEMNODE_DIR/${STR}"$'\n'
666 $vonDirFileProc "$STR"
668 elif [[ ${NODE_TYPE} == 'item
' ]]; then
669 $vonItemSubjectDirEntering "${DIR_TYPE}" "${SUBJECTDIR}" "${DIR_NAME}"
671 for NFEXT in ${FILE_EXT_LIST[@]}; do
672 STR_FMT="$(envar_get catalog::${NFEXT}::STR_FMT)"
674 FILE_NAME_LIST[$DIR_TYPE]+="touch ${OUTPUT_DIR}/$ITEMNODE_DIR/${STR}"$'\n'
676 $vonItemFileProc "$STR"
679 eval ITEM_DIR_NAME_${DIR_TYPE^^}="$DIR_NAME"
680 #elif [[ ${NODE_TYPE} == 'cont
' ]]; then
681 # $onContProc "$NNAME"
694 if [[ "$NODE_TYPE" == 'item
' ]]; then
695 ITEM_NCATAID="$NCATAID"
696 ITEM_NFULLCATAID="$NFULLCATAID"
700 ITEM_NODE_TYPE="$NODE_TYPE"
706 ##############################
708 ##############################
724 ###########################################################################
726 ###########################################################################