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 # it is a shlib for processing of program arguments.
14 # there are several part of args.shlib for args processing.
15 # @ several args desc-str-line. it describe a cmdline optoin
17 # @ desc-str dispatching result vars. it's the env var generated
18 # in desc-str-line processing. and it's used for actual args
20 # @ action function. it is included in desc-str-line for the
21 # option. when this option apeard in args, this function will
22 # be invoked to implement corresponding feature. if a option
23 # bring with a paramter arg, it would be the first paramter
24 # of action function. if the action function is not used by
25 # programer, use the env var defined in desc-str. when the
26 # value is 'enable', it means this option is used in cmdline.
27 # it's usefull for multi paramter processing.
28 # @ paramter helper. it's a part of usage string. invoking
29 # helper_gen to output the string.
30 # it's a usefull feature for developer on args processing.
31 # and the developer get benifit by using this shlib is that:
32 # @ just care about option name, and the output resualt of
33 # vars and action functions and desc-info. those info is
34 # associate by this shlib automatically.
35 # @ in normal developping, programer is writing code for feature
36 # implement, and append helper info at last. it may be cause
37 # a problem that the option implement is not syncronized to
38 # code implement. in desc-str-line, the paramter and implement
39 # action function can be seen directly by developer.
40 ############################################################
49 # @ code-trim: func name, dbg-info.
50 # @ combine param/vname/onproc into one opt.
51 # @ right boundary align.
53 # @ gen var define in c & sh
54 # @ insert dispathed var into src file.
55 # @ use imi file instead of var define in src file.
56 # @ cmdline hint append.
62 # @ the processing of description string bundary implemented by fold.
63 # but it works only in english. make some patch for it, and let it
64 # working in utf-8 charset.
65 # @ the right side limit will truncate the words in desc string.
66 # impove with fold. english words would not be truncated.
70 # @ append blank line display desc-str-line "|blank" in desc-str.
71 # @ add string after 'blank', and displayed for option category.
72 # @ multiple desc-str.
73 # @ dispatch debug info output by --debug option, or DBGOUTD_OUTPUT=1.
74 # @ the old version only dispaly strings without blank. now it can display
75 # english string with blanks.
80 # @ add OptDescParamPrint() after opt_desc_str_dispatch(), to judge if parameter desc
82 # @ if there are many opts in program, divid into several desc_str for debugging.
83 # @ if helper info display incorrect, read func helper_gen().
84 # @ if opt does not work, read the func prog_opt_proc(),
89 # @ display width auto-adapt to term_width, it can be disabled by setting
90 # fixed value in program, or add an ENVAR to disable this feature.
93 # this cmd enable alias feature in script. it is disabled in default.
94 shopt -s expand_aliases
97 ##############################
98 # section: public comment info
99 ##############################
103 ##############################
104 # section: variable define
105 ##############################
110 # prog $0 '<prog_desc>'
111 # param -<pchar> --<long-opt> ---<cmd-opt> =<value> %<pname> !<pproc> '<pdesc-str>'
115 # member variable of option paramter var.
127 # variable of dispatched paramter describe string
129 # those variable is used as an array.
130 # if it is a digital indexed array, it must be the variable used to store dispatched paramter.
131 # if it is a name string indexed array, it must be the variable updated by runtime arguments.
141 # array of shell script can not use string indexed array mixed with array.
142 # before declare an array, unset it first.
143 # TBD: this code just running at once, when multiple desc-str is used.
147 # not used currently.
150 declare -g -A -x p_char2idx
151 declare -g -A -x p_longopt2idx
152 declare -g -A -x p_cmd2idx
153 declare -g -A -x p_name2idx
160 declare -g -a actionlist
164 # option desciption framework for helper.
165 # -f, --file=<file-path> name paramter string. use this
166 # paramter as the operating file.
167 # |<<-1->|--------- 2 -------->|<-3->|<----- 4 ---—->|
168 # |<---------------------------- 5 ----------------------------->|
170 # 1:pname_blanks. blanks befor paramter name string.
171 pname_blanks
=${pname_blanks:-1}
172 # 2:pname_width. paramter string width, and blank prefix width.
174 # 3:desc_blanks. blanks before paramter describe string.
176 # 4: calculated by 'term_width - desc_blanks - pname_width - pname_blanks'
177 # 5: term_width, getting from code.
186 ##############################
187 # section: private function
188 ##############################
192 local f_ttyout
=$
(ps
-p $$
-o tty |
tail -n 1 | cut
-d ' ' -f1 2>/dev
/null
)
194 test -n "$f_ttyout" && export term_width
=$
(stty
-F /dev
/$f_ttyout size
2>&1 | cut
-d ' ' -f2 |
tr -d "'")
203 # get term width, to generate usage string adepted to screen size.
204 # when stdout is not a tty device, set a default value.
206 # this paramter is defined in other shlib
210 if test -z "$term_width"; then
211 term_width
=$
(__get_term_width
)
212 if [[ ! "$term_width" =~
[^
0-9] ]]; then
213 args_ttydev
=$
(ps
-p $$
-o tty |
tail -n 1 | cut
-d ' ' -f1)
215 # args_ttydev=$(ps -ajx | cut -d ' ' -f2 | grep -i "`ps -ajx | grep -i "$$" | cut -d ' ' -f4 | head -n 1`" | cut -d ' ' -f5)
217 test -z "$args_ttydev" && args_ttydev
=pts
/0
218 args_ttydev
="/dev/$args_ttydev"
219 export term_width
=$
(stty
-F $args_ttydev size
2>&1 | cut
-d ' ' -f2)
222 if [[ $term_width =~
"[a-zA-Z]" ]]; then
223 export term_width
=100
226 # dbgoutd "defined term_width=$term_width\n"
233 # copy dbgout code to here, this shlib can be used indepently.
236 if [[ ! "$(type dbgout 2>&1)" =~
"is a function" && ! "$(type dbgout 2>&1)" =~
"is aliased" ]]; then
241 dbgout_file
=${dbgout_file:-&2}
242 log_file
=${log_file:-/dev/null}
246 # dbgout <param-list>
250 echo -ne "$@" |
tee -a $log_file >&2 #>$dbgout_file
255 # re-define here to disable dbgoutd.
256 # declare -g -x DBGOUTD_OUTPUT=1
257 # set DBGOUTD_OUTPUT to 1 as an exported global var, the dbgout info will be outputted.
258 # it's usefull for new option implement, especially in test code..
262 if test -n "$DBGOUTD_OUTPUT"; then
268 ###########################################
269 # helper string output by dispatched vars.
272 # paramter descript string display is not a complex thing.
273 # there is something should be pay attension on, that the lenth
274 # limit on the right side. so we sould get the string lenth/width
276 # there are three type of char, and the corresponding lenth
278 # @ ascii char, it takes one byte, and use one unit of display char.
279 # @ gbk char, it takes two byte, and use two unit of display char.
280 # @ utf8 char, it may takes three byte, and use two unit of display
282 # the problem is, if the char type is mixed with those three type,
283 # how to get the display char width?
284 # ascii & gbk char is equal to the byte size of char. utf8 should
285 # be translated to gbk encode. then, those three type of char display
286 # width is equal to byte lenth of char.
287 # invoke "iconv -f utf-8 -t GBK", translate utf8 to gbk, calculate
288 # byte lenth, then convert back to utf8 encode. the byte size that we
289 # getted is the display char width.
292 # improve for words bundary truncating.
293 __oneline_desc_output
()
302 test "$offset" -ge "${#p_desc[$3]}" && return 0
304 # it's the length of string byte, but string length is the string char count.
305 len
=$
(( term_width
- pname_width
- desc_blanks
))
307 printf "%*s" $
(( pname_width
- $1 + desc_blanks
)) " "
310 # todo: this cmd cost more cpu resource.
312 # $len is the dispaly width of description string area.
313 # first, traslate it to gbk, let the byte size equal to dispaly char width, and cut $len char that equal
314 # to the width of dispaly area, and get the byte $cnt. in utf-8 envronment, it maybe cut a double or triple
315 # byte char, and it will leading error dispaly. so $len is not the truncate length it should be. use echo
316 # cmd to output string again, it will filer the uncorrect char that may be truncated by 'cut', and count
317 # the bytes of string, it's the actual byte cnt we should use for 'fold' to cut the string.
318 tmp
="`echo -ne "${p_desc[$3]:$offset}" | iconv -f utf-8 -t GBK 2> /dev/null | cut -c 1-$len`"
319 cnt
=`echo -ne "$tmp" | wc -c`
321 # then, do tralate operation again, and intert with a fold cmd to cut it by $cnt size, get the first line
322 # of the string, that's the string should be dispalyed on screen.
323 # this method compactive with utf-8 char dispaly, and english words bundary truncate. but it cost a bit more
325 tmp
="`echo -ne "${p_desc[$3]:$offset}" | iconv -f utf-8 -t GBK 2> /dev/null | fold -b -s -w $cnt - 2> /dev/null | iconv -f GBK -t utf-8 2> /dev/null`"
329 test -z "$tmp" && return 0
331 # get the char cnt of tmp that to be dispalyed
335 offset
=$
(( offset
+ size
))
341 # fsyntax: __rest_desc_output <width> <idx>
342 # fdesc: output multi-line string. if the first line is outputed, it
343 # display the rest string.
345 __rest_desc_output
()
349 # the string length of env var is the char number of string.
350 # the string size of env is the buffer byte count of string.
351 # if it is a gbk char string, 2 byte size equal to 2 char width.
352 # calculate string display width is count the byte of string transformed from
354 # len=$(( $term_width - $pname_blanks - $pname_width - $desc_blanks ))
356 for (( i
=0; i
<200; i
++ )); do
357 __oneline_desc_output
0 $1 $2
358 test "$?" == 0 && break
361 test "$i" = 200 && err
"err: $FUNCNAME(line$LINENO) loop exception.\n" && exit
364 ############################################################
365 # argument describe string and dispatching
366 # using regex to match string, instead of others.
367 # TBD: it can not be executed under non-bash shell program.
374 # [[ "${abc}" =~ \|([^|]+)\ \|-([^|]*)\ \|--([^|]*)\ \|---([^|]*)\ \|=[\<\|\[]?([^|]*)[\>\|\]]? ]] && echo ${BASH_REMATCH[@]}
375 # |param |- |--logfile |--- |= | param logfile
377 # \|([^|]+)\ \|-([^|]*)\ \|--([^|]*)\ \|---([^|]*)\ \|=[\<|\[]?([^\|\>]*)[\>|\]?\ \|%[\<|\[]?([^\|\>]*)[\>|\]?\ \|=[\<|\[]?([^\|\>]*)[\>|\]?[\>|\]]?\ \|[\']?([^\|\>]*)[\']?
379 # it's a fixed syntax for desc-str-line.
382 # CONTENT="|param |-e |--envchk |---envchk |= |%<envchk> |&<on_envchk> |'execute environment check for compile.'"
383 # debug this format sting in several parts
385 fmt+="\|([[:alnum:]_]+)[[:space:]]*"
386 fmt+="\|-([[:alnum:]_]*)?[[:space:]]*"
387 fmt+="\|--([[:alnum:]-]*)?[[:space:]]*"
388 fmt+="\|---([[:alnum:]_]*)?[[:space:]]*"
389 fmt+="\|=([\<|\[]?[[:alnum:][:punct:]]*[]|\>]?)?[[:space:]]*"
390 fmt+="[\|]%[\<|\[]?([[:alnum:]_]*)?[]|\>]?[[:space:]]*"
391 fmt+="\|&[\<|\[]?([[:alnum:]_]*)?[]|\>]?[[:space:]]*"
392 fmt+="\|[']?([^\']*)?"
394 if [[ "${1}" =~
$fmt ]]; then
397 for ((x
=0; $x < ${#BASH_REMATCH[@]}; x
++)); do
398 param
[$x]="${BASH_REMATCH[$x]}"
400 elif [[ "${1}" =~ ^
[:blank
:]*[\|
](prog
) ]]; then
403 param
[0]="${BASH_REMATCH[0]}"
404 param
[1]="${BASH_REMATCH[1]}"
405 elif [[ "${1}" =~
[\|
](blank
)[\
]*[\']?
([^
\']*)?
[\']?
]]; then
408 param
[0]="${BASH_REMATCH[0]}"
409 param
[1]="${BASH_REMATCH[1]}"
410 param
[2]="${BASH_REMATCH[2]}"
413 declare -g -a param
=""
417 desc_param_setting
()
419 test "${param:-111}" = 111 && return
421 test -n "${param[2]}" && p_char[$idx]=${param[2]:0:2} && p_char2idx["${param[2]:0:1}"]=$idx
422 test -n "${param[3]}" && p_longopt[$idx]=${param[3]} && p_longopt2idx["${param[3]}"]=$idx
423 test -n "${param[4]}" && p_cmd[$idx]=${param[4]} && p_cmd2idx["${param[4]}"]=$idx
426 if test "${param[5]:0:1}" = "<" ; then
428 elif test "${param[5]:0:1}" = "[" ; then
433 param
[5]=${param[5]:1:-1}
434 test -n "${param[5]}" && p_value
[$idx]="${param[5]}"
436 # option name, proc function
437 test -n "${param[6]}" && p_name[$idx]=${param[6]} && p_name2idx["${param[6]}"]=$idx
438 test -n "${param[7]}" && p_proc
[$idx]=${param[7]}
441 test -n "${param[8]}" && p_desc
[$idx]="${param[8]}"
443 dbgoutdd
"============================================\n"
445 dbgoutdd
"p_char[$idx]=$tmp'\n"
446 tmp
=${p_char[$idx]:0:1}
447 [[ -n "$tmp" && "$tmp" != ':' ]] && dbgoutdd
"p_char2idx[$tmp]='${p_char2idx[$tmp]}'\n"
448 tmp
=${p_longopt[$idx]}
449 dbgoutdd
"p_longopt[$idx]='${tmp}'\n"
450 [[ -n "$tmp" ]] && dbgoutdd
"p_longopt2idx[$tmp]='${p_longopt2idx[$tmp]}'\n"
452 dbgoutdd
"p_cmd[$idx]='${tmp}'\n"
453 [[ -n "$tmp" ]] && dbgoutdd
"p_cmd2idx[$tmp]='${p_cmd2idx[$tmp]}'\n"
454 dbgoutdd
"p_value[$idx]='${p_value[$idx]}'\n"
456 dbgoutdd
"p_name[$idx]='${tmp}'\n"
457 [[ -n "$tmp" ]] && dbgoutdd
"p_name2idx[$tmp]='${p_name2idx[$tmp]}'\n"
458 dbgoutdd
"p_proc[$idx]='${p_proc[$idx]}'\n"
459 dbgoutdd
"p_desc[$idx]='${p_desc[$idx]}'\n"
461 declare -l OPT_PFX
=" "
466 # due to p_char[] store short opt with ':', it might be only ':' without short opt char.
467 # maybe it should append these judement below.
468 # && "${p_char[$idx]:0:1}" != ':'
470 if [[ -n "${p_char[$idx]}" && "${p_char[$idx]:0:1}" != ':' ]]; then
471 content
+="-${p_char[$idx]:0:1}"
472 p_shortparam
+="|${p_char[$idx]}"
480 [[ $
(( $len + ${#p_cmd[$idx]} + 2 )) -gt $pname_width ]] && content
+="$(printf '\n%*s' $pname_blanks ' ')" && len
=0
481 if test -n "${p_cmd[$idx]}" ; then
482 content
+="${OPT_PFX}${p_cmd[$idx]}"
483 p_cmdparam
+="|${p_cmd[$idx]}"
484 len
=$
(( $len + ${#p_cmd[$idx]} + 2 ))
488 [[ $
(( $len + ${#p_longopt[$idx]} + 4 )) -gt $pname_width ]] && content
+="$(printf '\n%*s' $pname_blanks ' ')" && len
=0
489 test -n "${p_longopt[$idx]}" && content+="${OPT_PFX}--${p_longopt[$idx]}" && p_longparam+="|${p_longopt[$idx]}${p_char[$idx]:1}" && len=$(( $len + ${#p_longopt[$idx]} + 4 ))
491 test "$
(( $len + ${#p_value[$idx]} + 3 ))" -gt $pname_width && content+="$
(printf '\n%*s' $pname_blanks ' ')" && len=0
492 test -n "${p_value[$idx]}" && content+="=<${p_value[$idx]}>" && len=$(( $len + ${#p_value[$idx]} + 3 ))
497 ##############################
498 # section: public function
499 ##############################
502 # fsyntax: OptDescParamPrint
503 # fdesc: output environment variable of dispatched option describe string.
507 dbgout
"##########################\n"
508 dbgout
"p_prog=$p_prog\n"
509 dbgout
"p_progdesc=$p_progdesc\n"
511 dbgout
"p_shortparam=$p_shortparam\n"
512 dbgout
"p_longparam=$p_longparam\n"
513 dbgout
"p_cmdparam=$p_cmdparam\n"
515 dbgout
"p_pcnt=$p_pcnt\n"
517 for (( i
=0; i
<$p_pcnt; i
++ )); do
519 dbgout
" p_char[$i]=${p_char[$i]}\n"
520 dbgout
" p_longopt[$i]=${p_longopt[$i]}\n"
521 dbgout
" p_cmd[$i]=${p_cmd[$i]}\n"
522 dbgout
" p_value[$i]=${p_value[$i]}\n"
523 dbgout
" p_name[$i]=${p_name[$i]}\n"
524 dbgout
" p_proc[$i]=${p_proc[$i]}\n"
525 dbgout
" p_desc[$i]=\"${p_desc[$i]}\"\n"
528 dbgout
"pname_width=$pname_width\n"
529 dbgout
"pname_blanks=$pname_blanks\n"
530 dbgout
"desc_blanks=$desc_blanks\n"
532 dbgout
"term_width=$term_width\n"
536 ########################################
537 # main feature of args.shlib:
538 # @ dispatching desc-str to env vars which has a pfx 'p_'.
539 # @ resovle run time program args by 'p_*' env vars, set corresponding var value,
540 # and invoke action proc function.
541 # @ generate helper string by 'p_*' env vars
545 # fsyntax: helper_gen
546 # fdesc: generate helper string by paramter, and output it to the variable which
547 # specified in paramter. invoke this function before opt_helper() dispaly helper.
559 acnt
=$idx #${#p_char[@]}
561 for (( i
=0; $i <= $acnt; i
++ )); do
565 # no description is seems as a blank line tag.
566 test -z "${p_desc[$i]}" && echo && continue
568 # this is a category description string.
569 if [[ "${p_char[$i]}" == '::' || "${p_char[$i]}" == ':' || -z "${p_char[$i]}" ]]; then
570 [[ -z "${p_longopt[$i]}" && -z "${p_cmd[$i]}" ]] && echo -ne "${p_desc[$i]}\n" && continue
573 printf "%*s" $pname_blanks " "
576 # if test "$OPT_PFX" = " "; then
577 declare -l OPT_PFX
=" "
582 # this two cmd display nothing on screen.
583 # this string is filtered automatically, it is treated as the paramter for echo.
586 # so output this string by two step. one is '-', then is 'n' or 'e'
587 if test -n "${p_char[$i]:0:1}" && test "${p_char[$i]:0:1}" != ":" ; then
589 echo -ne "${p_char[$i]:0:1}"
596 if test -n ${p_cmd[$i]} && test "$(( $len + ${#p_cmd[$i]} + 2 ))" -gt $pname_width ; then
597 __oneline_desc_output
$len $pname_width $i
598 printf "%*s" $pname_blanks " "
601 if test -n "${p_cmd[$i]}"; then
602 echo -ne "${OPT_PFX}${p_cmd[$i]}"
603 len
=$
(( $len + ${#p_cmd[$i]} + 2 ))
607 if test "$(( $len + ${#p_longopt[$i]} + 4 ))" -gt $pname_width ; then
608 __oneline_desc_output
$len $pname_width $i
609 printf "%*s" $pname_blanks " "
612 test -n "${p_longopt[$i]}" && echo -ne "${OPT_PFX}--${p_longopt[$i]}" && len=$(( $len + ${#p_longopt[$i]} + 4 ))
614 if test "$
(( $len + ${#p_value[$i]} + 3 ))" -gt $pname_width ; then
615 __oneline_desc_output $len $pname_width $i
616 printf "%*s
" $pname_blanks " "
617 len=$(( pname_blanks + 4 ))
619 if test "${p_char[$i]:1}" = "::" || test "${p_char[$i]}" = "::" ; then
620 test -n "${p_value[$i]}" && echo -ne "=[${p_value[$i]}]" && len=$(( $len + ${#p_value[$i]} + 3 ))
622 test -n "${p_value[$i]}" && echo -ne "=<${p_value[$i]}>" && len=$(( $len + ${#p_value[$i]} + 3 ))
625 test "$offset" -ge "${#p_desc[$i]}" && echo && continue
627 __oneline_desc_output $len $pname_width $i
630 __rest_desc_output $pname_width $i
635 # fsyntax: opt_helper <output-var>
636 # fsyntax: generate helper string by the dispatched var.
637 # if <output-var> is '-', output to stdout instead of var.
641 local tmp=$(__get_term_width)
643 if test -n "$tmp" && test "$term_width" -gt "$tmp" || test -z "$helper"; then
645 helper="`helper_gen`"
648 # TBD: iconv here at a time to save time coast.
650 test -n "$helper" && echo "$helper" # | iconv -f GBK -t utf-8 -c -s 2>/dev/null
652 test -n "$helper" && echo "$helper" # | iconv -f GBK -t utf-8 -c -s 2>/dev/null
656 # TBD: init the value to 0 if first init.
657 # it is defined as a global var, used for multiple desc-str dispathing.
661 # fsyntax: opt_desc_str_dispatch <desc_str_var_name>
662 # fdesc: description string dispatch to p_* variables.
664 opt_desc_str_dispatch ()
678 # resolve command line descript string and save to p_ variables.
681 # ARGS=( $(eval echo -ne "$ARGS" | tr '\n' '@' | tr -s ' ' ) )
683 # sed -E "s
/[\r\n]/@
/g
"
684 # this cmd cannot replace \r with @.
685 # [https://blog.51cto.com/u_15127525/4013659]
686 # in sed, it process text every time in a line. newline is a spacial char.
687 # it will append trailing newline after one line data processing.
688 # to solv this problem, we should known about branch condition cmd, pattern
689 # space, and hold space.
690 # run sed cmd in two lines, use this cmd:
691 # sed -E ":a
;N
;s
/[\r\n]/@
/g
;ta
"
692 # sed -E ':a;N;s/[\n\r]{1,2}[\|]/@\|/g;ta'
693 ARGS=( $(eval echo -ne "$ARGS" | sed -E 's/^[\|]/@\|/g' ) )
695 # declare -p ARGS >&2
696 # dbgoutdd "ARGS
=${ARGS[@]}\n"
701 test "$pname_width" = 0 && pname_width=$(( ${term_width:-80} / 2 ))
703 for (( i=1; i<$cnt ; i++ )) do
704 test "${ARGS[$i]:0:1}" = '#' && continue
706 # str_dispatch_method2 "${ARGS[$i]}"
707 str_dispatch "${ARGS[$i]}"
709 if [[ ${param[1]} == "prog
" ]]; then
711 p_progdesc=${param[3]//\'/} #'
712 elif [[ ${param[1]} =~ "blank
" ]]; then
714 test -n "${param[2]}" && p_desc[$idx]="${param[2]}"
716 elif [[ ${param[1]} =~ "param
" ]]; then
718 # use string match to implement this code.
721 # desc_param_setting_method2
726 tmp="${ARGS[$i]//[ |\t]/}"
727 if test -z "${tmp}"; then
729 elif [[ "${ARGS[$i]}" =~ [^\ ] ]]; then
730 # if there is no header with 'param' or 'prog'
731 # and it's not a blank line, it's maybe a descript string line
732 # continued from last config data.
736 if [[ -z $tmp || ! $tmp =~ "-" && ! $tmp =~ "=" && ! $tmp =~ "%" && ! $tmp =~ "!" ]]; then
737 tmp="${ARGS[$i]#*\'}"
739 p_desc[$(( $idx - 1 ))]+="$tmp"
749 # re-generate if pname_width equal to 0.
750 if test "$width" = 0 ; then
756 for (( i=$(( ${#content[@]} - 1 )); i>=0; i-- )); do
758 test "$tmp" -lt "$cnt" && tmp="$cnt"
761 # update value of pname_width
762 pname_width=$(( $tmp + 1 ))
767 # fdesc: for '-<c> <param>', it processed as "-<c
> '' -- <param
>".
768 # this func are used to fix this problem.
777 param=( ${param##*--} )
778 cnt=$(($# - ${#param[@]}))
779 for (( i=1; $i < $# ; i++ )); do
780 eval test "\"\
${$i}\"" = '--' && break;
782 # NULL param means there are opt param maybe after '--'
783 if eval test -z "\"\
${$i}\"" || eval test "\"\
${$i}\"" = "''" ; then
784 if test -z "${param[$j]}" ; then
787 echo -ne "${param[$j]} "
798 echo "-- ${param[@]}"
799 # echo -ne "-- ${param[@]}\n" >&2
803 # fsyntax: prog_opt_proc <arg-list>
804 # fdesc: process options in cmd arg, save the coressponding flag variable to 'enable', and
805 # append process function to actionlist.
806 # save paramters in cmd arg to actionlist with process function.
807 # at last, invoke functions in actionlist.
827 dbgoutdd "=================================================\n"
830 short_opt=${p_shortparam:1}
831 short_opt=${short_opt//|/}
832 dbgoutdd "short_opt
= $short_opt\n"
835 long_opt=${p_longparam:1}
836 long_opt=${long_opt//|/,}
837 dbgoutdd "long_opt
= $long_opt\n"
839 # for ((i=1; i<=$#; i++)); do eval echo "\
$i=\
${$i}"; done
842 # paramter format translating.
843 # --long=a => --long a
844 # paramter maybe is a string with blanks in quote,
845 # if $@ directly, quoted string will be treated as several words.
846 # put "$@
" to cmd string,
847 # ARGS="`eval $ARGS "$@"`"
851 # there is an error when -o option with no parameter, eg: $short_opt is NULL.
852 # add quote here to generate a parameter even if $short_opt is NULL string.
854 ARGS="getopt
-o \"$short_opt\" -l ${long_opt},insert-helper
,inc-path
,param-desc-str-alian
--"
855 dbgoutdd "getopt cmd
: ARGS
= $ARGS $@
\n"
856 ARGS=( `$ARGS "$@
"` )
861 if test "$?
" != 0 ; then
862 err "Fail to get args.
\n"
866 dbgoutdd "get opt resualt
: ARGS
= $ARGS\n"
868 ARGS="$
(arg_proc
${ARGS[@]})"
871 eval set -- "${ARGS}"
873 dbgoutdd "ARGS
= $@
\n"
874 # generate actionlist[] by argument
876 for ((i=0; i < 1000 ; i++)) do
879 dbgoutdd "\
$1 = $1\n"
880 test -z "$1" && break
883 dbgoutdd "param
--\n"
885 test "$argflag" = 1 && break
895 dbgout "param_insert_helper
()\n"
901 dbgout "param_inc_path
()\n"
906 --param-desc-str-alian )
907 dbgout "param_param_desc_str_alian
()\n"
908 param_param_desc_str_alian
915 index=${p_longopt2idx[$param]}
916 test -z $index && break
920 # dbgoutdd "$1,$2,$3\n"
923 index=${p_char2idx[$param]}
925 dbgoutdd "=================================================\n"
926 dbgoutdd "option
-$param processing ...
\n"
927 dbgoutdd "\
${!p_char2idx[@]} = ${!p_char2idx[@]}\n"
928 dbgoutdd "\
${p_char2idx[@]} = ${p_char2idx[@]}\n"
929 dbgoutdd "\
${p_char2idx[\"$param\"]} = ${p_char2idx[$param]}\n"
930 dbgoutdd "param
= $param\n"
931 dbgoutdd "index
= $index\n"
933 test -z "$index" && break
938 index=${p_cmd2idx[$param]}
940 test -z "$index" && break
946 test -z "$index" && dbgout "err
: param
($param) exist
, but it
's index value not found.\n" && continue
948 # paramter output for debugging
949 dbgoutdd "\$1 = $1\n"
950 dbgoutdd "\$2 = $2\n"
951 dbgoutdd "index = $index\n"
952 dbgoutdd "\${p_value[$index]} = ${p_value[$index]}\n"
954 if test -n "${p_value[$index]}" ; then
955 declare -g ${p_value[$index]}="$2"
956 value=$(eval echo \$${p_value[$index]})
958 declare -g ${p_name[$index]}="enable"
961 proc=${p_proc[$index]}
963 if test ! -z "$value"; then
970 # option action function list generating.
971 dbgoutdd "value = $value\n"
972 dbgoutdd "proc = $proc()\n"
973 test -n "$proc" && actionlist="$actionlist
976 # execute paramter proc function.
980 actionlist=( $actionlist )
991 cnt=${#actionlist[@]}
992 for (( i=0; i < cnt; i++ )); do
993 dbgoutdd "==============================================\n"
994 dbgoutdd "invoke: ${actionlist[$i]}\n"
995 ${actionlist[$i]} $general_param
998 test "$i" = "${#actionlist[@]}" && dbgoutdd "==============================================\n"
1005 # the code below is reserved, because it's used
for optimizing cpu cost
in some system
1010 # tmp_usage_desc=`echo -ne "${usage_desc_str}" | iconv -f utf-8 -t GBK 2> /dev/null | cut -c 1-$len | iconv -f GBK -t utf-8 2> /dev/null`
1011 # [[ -z $tmp_usage_desc ]] && return
1014 # fsyntax: prog_opt_dispatch <prog-arg-list>
1015 # fdesc: dispatch usage_desc_str to vars, and resolve program args by those
1017 # normally, it is not used when developer want to let the desc-str to be a re-usable
1018 # desc-str in another program, which 'source' the program, to use the desc-str.
1020 prog_opt_dispatch
()
1023 # TBD: translate utf8 to gbk at a time, to avoid iconv invoking every line data.
1025 # tmp_usage_desc=`echo -ne "${usage_desc_str}" | iconv -f utf-8 -t GBK 2> /dev/null`
1026 # [[ -z $tmp_usage_desc ]] && return
1028 opt_desc_str_dispatch usage_desc_str
;
1030 # do not generate helper string if it is not -h paramter.
1031 # it takes more cpu resource.
1032 # helper="`helper_gen`"
1039 ##############################
1040 # section: file tail
1041 ##############################
1050 dbgout
"usage_desc_str = $usage_desc_str\n"
1054 dbgout
"#######################################\n"
1056 # 这里的-i参数为可选,但参数是以-ixxx的形式将参数xxx传递到程序的。pp0
1057 # -i xxx的方式不会识别参数。像是gcc中-m参数的使用。
1059 prog_opt_testing
-a --test params aaa
-iabc -x 123
1061 dbgout
"#######################################\n"
1069 dbgout
"#######################################\n"
1071 prog_opt_testing
--help
1082 # wc方式以字节长度计数,但运行费时,使用字符长度,在英文字母为字符串的参数信息中,等同于字节数。
1083 # if [[ $(( $len + "`echo \"${p_cmd[$i]}\" | wc -L`" + 2 )) -gt $pname_width ]]; then
1092 # parmater list. used for enum paramter var.
1098 # foo () { ARGS="$(getopt -o lS:y::n:LFraAt:b:e:x:RBscuvqfj:M:d:O:pmgVh -l list,save:,sync::,num:,failed-begin,failed,ignor-err,all,test:,begin:,end:,exclude:,rollup,rollback,set,clean,update,verbose,quiet,force,multi-task:,matching:,dir:,output-dir:,print-vars,mono,logfile,version,help,debug,insert-helper,inc-path,param-desc-str-alian -- "$@")"; echo "ARGS=\"$ARGS\""; eval set -- "$ARGS"; echo param="$@"; echo "\$1='$1'"; echo "\$2='$2'"; for ((i=1; i<=$#; i++)); do eval echo "\\\$$i=\"\${$i}\""; done; }
1103 # ARGS="$(getopt -o lS:y::n:LFraAt:b:e:x:RBscuvqfj:M:d:O:pmgVh -l list,save:,sync::,num:,failed-begin,failed,ignor-err,all,test:,begin:,end:,exclude:,rollup,rollback,set,clean,update,verbose,quiet,force,multi-task:,matching:,dir:,output-dir:,print-vars,mono,logfile,version,help,debug,insert-helper,inc-path,param-desc-str-alian -- "$@")";
1104 # echo "ARGS=\"$ARGS\"";
1105 # eval set -- "$ARGS";
1109 # for ((i=1; i<=$#; i++)); do
1110 # eval echo "\\\$$i=\"\${$i}\"";
1113 # $ foo -M '<861874> [citem] aqstk "stack and queue data structure with array feature"'
1114 # ARGS=" -M '<861874> [citem] aqstk "stack and queue data structure with array feature"' --"
1115 # param=-M <861874> [citem] aqstk "stack and queue data structure with array feature" --
1117 # $2='<861874> [citem] aqstk "stack and queue data structure with array feature"'
1119 # $2=<861874> [citem] aqstk "stack and queue data structure with array feature"
1126 blank_param_setting
()
1128 p_char
[$idx]=""; p_char2idx
["${param[2]:0:1}"]=""
1129 p_longopt
[$idx]=""; p_longopt2idx
["${param[3]}"]=""
1130 p_cmd
[$idx]=""; p_cmd2idx
["${param[4]}"]=""
1153 # fsyntax: __oneline_desc_output <param-str-len> <width> <idx>
1154 # fdesc: output single line option description string.
1156 __oneline_desc_output_bak
()
1165 test "$offset" -ge "${#p_desc[$3]}" && return 0
1167 # it's the length of string byte, but string length is the string char count.
1168 len
=$
(( term_width
- pname_width
- desc_blanks
))
1170 printf "%*s" $
(( pname_width
- $1 + desc_blanks
)) " "
1173 # todo: this cmd coast more cpu resource.
1175 tmp
=`echo -ne "${p_desc[$3]:$offset:$len}" | iconv -f utf-8 -t GBK 2> /dev/null | cut -c 1-$len | iconv -f GBK -t utf-8 2> /dev/null`
1176 # tmp=`echo -ne "${p_desc[$3]:$offset:$len}" | cut -c 1-$len`
1177 test -z "$tmp" && return 0
1179 cnt
=`echo -ne "$tmp" | wc -c`
1181 tmp
=`echo -ne "$tmp" | fold -b -s -w $cnt - 2> /dev/null`
1184 offset
=$
(( offset
+ size
))