A generalized option evaluation loop is implemented in snippet sh_b.opt-loop. This chapter describes the algorithm employed.
BNF for simple scripts:
command: command-name
| command-name options
| command-name arguments
| command-name options arguments
options : option
| option options
option: option-symbol
| option-symbol argument
BNF for script implementing a command shell:
command-shell: command-shell-name
| command-shell-name options
| command-shell-name command
| command-shell-name options command
# ::here::
opt_debug=0
opt_arg='default arg'
pass_opts=
while :
do
test x${1+set} = xset || break
case "${1}" in
## (progn (forward-line 1) (snip-insert "sh_b.opt-option" t t "sh" " --key skip_for_update --key opt-minimalx") (insert "\n"))
# Defining opt_short as `o`, opt_long as `option`, opt_arg as `ARG` => creates option: -o, --option ARG; the value `::fillme::` is considered blank, it does not have to be removed
# (let ((opt_short "::fillme::") (opt_long "::fillme::") (opt_arg "::fillme::")) (forward-line 2) (snip-insert "sh_b.opt-option" t t "sh" (concat " --key opt-minimalx --key skip_for_update --key opt_short --value " opt_short " --key opt_long --value " opt_long " --key opt_arg --value " opt_arg)))
# ::here::
-d|--d|--de|--deb|--debu|--debug) # --debug
opt_debug=1
pass_opts="${pass_opts}"' --debug'
;;
-a|--a|--ar|--arg) # --arg OPT-ARG
opt_arg="${2-}"
test x"${2+set}" = xset && shift
pass_opts="${pass_opts}"' --arg '"${opt_arg}"
#pass_opts="${pass_opts}"' --arg '"$( single_quote_enclose "${opt_arg}" )"
;;
-\?|-h|--h|--he|--hel|--help) # --help
usage; exit 0
pass_opts="${pass_opts}"' --help'
;;
--u|--um|--uml|--umlx) # --umlx RX[:TYP]
opt_umlx="${2-}"
test x"${2+set}" = xset && shift
opt_umlx_match="$( printf "%s\n" "${opt_umlx}" | ${SED__PROG-sed} 's,^\([^:]*\)\(:\([^:]*\)\)*.*,\1,' )"
opt_umlx_type="$( printf "%s\n" "${opt_umlx}" | ${SED__PROG-sed} 's,^\([^:]*\)\(:\([^:]*\)\)*.*,\3,' )"
out_filt_conv ()
{
_type="${1}"
case "${_type}" in
## (progn (forward-line 1) (snip-insert "sh_b.case_patterns_for_actions" t t "sh" " --key actions --value '::fillme::'") (insert ""))
v|vi|vie|view) _type='svg';;
esac
if test -z "${_type}"
then
cat
else
plantuml -t"${_type}" -pipe
fi
}
out_filt_disp ()
{
_type="${1}"
case "${_type}" in
## (progn (forward-line 1) (snip-insert "sh_b.case_patterns_for_actions" t t "sh" " --key actions --value '::fillme::'") (insert ""))
v|vi|vie|view) _type='view';;
esac
if test "${_type}" != view
then
cat
else
display
fi
}
(
if test -n "${opt_umlx_match}"
then
line_diversion.py --match "${opt_umlx_match}" "${prog_path-${0}}"
else
line_diversion.py "${prog_path-${0}}"
fi
) \
| out_filt_conv "${opt_umlx_type}" \
| out_filt_disp "${opt_umlx_type}"
exit 0
#pass_opts="${pass_opts}"' --umlx '"${opt_umlx}"
#pass_opts="${pass_opts}"' --umlx '"$( single_quote_enclose "${opt_umlx}" )
;;
--) # end of options
shift; break;;
-) # stdin
break;;
-*) # unknown option
echo >&2 "${prog_name-$( basename "${0}" )}: error: unknown option \`${1}'"
exit 1
break
;;
*)
break;;
esac
shift
done
sh_b.opt-loop
contains shell comments with emacs lisp code for
inserting an option definiton:
;; opt_short: o | opt_long: option | opt_arg: ARG => description: -o, --option ARG || ::fillme:: is considered blank, it does not have to be removed
(let ((opt_short "::fillme::")
(opt_long "::fillme::")
(opt_arg "::fillme::"))
(forward-line 1)
(snip-insert "sh_b.opt-option" t t "sh"
(concat " --key opt_short --value " opt_short
" --key opt_long --value " opt_long
" --key opt_arg --value " opt_arg)))
The ::fillme:: tag is interpreted as if the parameter was blank. I.e., the ::fillme:: tags do not have to be deleted, only replaced as necessary.
The following Emacs Lisp expression, which does not define any of opt_short
, opt_long
and opt_arg
,
(progn
(forward-line 1)
(snip-insert "sh_b.opt-option" t t "sh"))
results in the following snippet shell command and output:
>>>snc --mode 'sh' --key 'filename' --value 'sh_b.opt-option' --process --replace '/home/ws/snippets/sh_b.opt-option'
#
opt_=0
) #
opt_=1;;
The following Emacs Lisp expression, which defines opt_short
as ::fillme::, opt_long
as ::fillme:: and opt_arg
as ::fillme::,
(let ((opt_short "::fillme::")
(opt_long "::fillme::")
(opt_arg "::fillme::"))
;; ...
)
results in the following snippet shell command and output:
>>>snc --mode 'sh' --key 'filename' --value 'sh_b.opt-option' --key opt_short --value ::fillme:: --key opt_long --value ::fillme:: --key opt_arg --value ::fillme:: --process --replace '/home/ws/snippets/sh_b.opt-option'
#
opt_=0
) #
opt_=1;;
The following Emacs Lisp expression, which defines opt_short
as q, opt_long
as quiet-day and opt_arg
as ::fillme::,
(let ((opt_short "q")
(opt_long "quiet-day")
(opt_arg "::fillme::"))
;; ...
)
results in the following snippet shell command and output:
>>>snc --mode 'sh' --key 'filename' --value 'sh_b.opt-option' --key opt_short --value q --key opt_long --value quiet-day --key opt_arg --value ::fillme:: --process --replace '/home/ws/snippets/sh_b.opt-option'
# -q, --quiet-day
opt_quiet_day=0
-q|--q*) # --quiet-day
opt_quiet_day=1;;
The following Emacs Lisp expression, which defines opt_short
as q, opt_long
as ::fillme:: and opt_arg
as INT,
(let ((opt_short "q")
(opt_long "::fillme::")
(opt_arg "INT"))
;; ...
)
results in the following snippet shell command and output:
>>>snc --mode 'sh' --key 'filename' --value 'sh_b.opt-option' --key opt_short --value q --key opt_long --value ::fillme:: --key opt_arg --value INT --process --replace '/home/ws/snippets/sh_b.opt-option'
# -q INT
opt_q=''
-q) # INT
opt_q="${2-}"
test x"${2+set}" = xset && shift;;
The following Emacs Lisp expression, which defines opt_short
as q, opt_long
as quiet-day and opt_arg
as INT,
(let ((opt_short "q")
(opt_long "quiet-day")
(opt_arg "INT"))
;; ...
)
results in the following snippet shell command and output:
>>>snc --mode 'sh' --key 'filename' --value 'sh_b.opt-option' --key opt_short --value q --key opt_long --value quiet-day --key opt_arg --value INT --process --replace '/home/ws/snippets/sh_b.opt-option'
# -q, --quiet-day INT
opt_quiet_day=''
-q|--q*) # --quiet-day INT
opt_quiet_day="${2-}"
test x"${2+set}" = xset && shift;;
The following Emacs Lisp expression, which defines opt_short
as ::fillme::, opt_long
as quiet-day and opt_arg
as INT,
(let ((opt_short "::fillme::")
(opt_long "quiet-day")
(opt_arg "INT"))
;; ...
)
results in the following snippet shell command and output:
>>>snc --mode 'sh' --key 'filename' --value 'sh_b.opt-option' --key opt_short --value ::fillme:: --key opt_long --value quiet-day --key opt_arg --value INT --process --replace '/home/ws/snippets/sh_b.opt-option'
# --quiet-day INT
opt_quiet_day=''
--q*) # --quiet-day INT
opt_quiet_day="${2-}"
test x"${2+set}" = xset && shift;;
# ||<-snap->|| if defined opt-minimal
# ||<-snap->|| alias opt-minimal rem
# ||<-snap->|| alias opt-not-minimal skip
# ||<-snap->|| subst opt-minimal-x
# ||<-snap->|| subst comm_activity @|empty@ #@empty@a99
# ||<-snap->|| subst case_short_end ;;
# ||<-snap->|| subst case_long_end
# ||<-snap->|| else
# ||<-snap->|| alias opt-minimal skip
# ||<-snap->|| alias opt-not-minimal rem
# ||<-snap->|| subst opt-minimal-x x
# ||<-snap->|| subst comm_activity @|empty@ #@empty@a0
# ||<-snap->|| subst case_short_end
# ||<-snap->|| subst case_long_end ;;
# ||<-snap->|| fi !defined opt-minimal
# ||<-snap->|| alias sh_b.opt-option rem
# ||<-snap->|| if !defined sh_b.opt-option
# ||<-snap->|| if defined skip_for_new
# ||<-snap->|| alias sh_b.opt-option skip
# ||<-snap->|| fi defined skip_for_new
# ||<-snap->|| fi !defined sh_b.opt-option
# ||<-snap->|| rem setup defaults
# ||<-snap->|| subst have_opt no
# ||<-snap->|| default opt_short
# ||<-snap->|| subst dash_opt_short
# ||<-snap->|| subst opt_short_long_comma
# ||<-snap->|| subst opt_short_long_bar
# ||<-snap->|| default opt_long
# ||<-snap->|| subst opt_name
# ||<-snap->|| subst dash_opt_long
# ||<-snap->|| subst opt_long_first
# ||<-snap->|| subst opt_long_cases
# ||<-snap->|| subst star_opt_long
# ||<-snap->|| subst comm_opt
# ||<-snap->|| default opt_arg
# ||<-snap->|| subst have_arg no
# ||<-snap->|| subst opt_arg_sep
# ||<-snap->|| rem ignore ::fillme:: tags
# ||<-snap->|| if eq opt_init ::fillme::
# ||<-snap->|| undef opt_init
# ||<-snap->|| fi
# ||<-snap->|| if eq opt_short ::fillme::
# ||<-snap->|| subst opt_short
# ||<-snap->|| fi
# ||<-snap->|| if eq opt_long ::fillme::
# ||<-snap->|| subst opt_long
# ||<-snap->|| fi
# ||<-snap->|| if eq opt_arg ::fillme::
# ||<-snap->|| subst opt_arg
# ||<-snap->|| fi
# ||<-snap->|| rem setup opt_short
# ||<-snap->|| if !eq opt_short @|empty@
# ||<-snap->|| subst have_opt yes
# ||<-snap->|| subst dash_opt_short -
# ||<-snap->|| if !eq opt_long @|empty@
# ||<-snap->|| subst opt_short_long_bar |
# ||<-snap->|| subst opt_short_long_comma ,@|space@
# ||<-snap->|| else
# ||<-snap->|| subst comm_opt @|empty@ # @||dash_opt_short@@||opt_short@
# ||<-snap->|| fi
# ||<-snap->|| fi
# ||<-snap->|| rem setup opt_long
# ||<-snap->|| if !eq opt_long @|empty@
# ||<-snap->|| subst have_opt yes
# ||<-snap->|| subst dash_opt_long --
# ||<-snap->|| subst star_opt_long *
# ||<-snap->|| subst comm_opt @|empty@ # @|dash_opt_long@@|opt_long@
# ||<-snap->|| define opt_name process
# ||<-snap->|| exec dump !process replace
printf "%s\n" '@opt_long@' | ${SED__PROG-sed} 's,[^0-9A-Za-z],_,g'
# ||<-snap->|| exec
# ||<-snap->|| define opt_name
# ||<-snap->|| define opt_long_first process
# ||<-snap->|| exec dump !process replace
printf "%s\n" '@opt_long@' | ${CUT__PROG-cut} -c 1
# ||<-snap->|| exec
# ||<-snap->|| define opt_long_first
# ||<-snap->|| subst pass_opt @dash_opt_long@@opt_long@
# ||<-snap->|| else
# ||<-snap->|| subst opt_name @opt_short@
# ||<-snap->|| subst pass_opt @dash_opt_short@@opt_short@
# ||<-snap->|| fi
# ||<-snap->|| trim right
# ||<-snap->|| define opt_option_templates
# Defining opt_short as `o`, opt_long as `option`, opt_arg as `ARG` => creates option: -o, --option ARG; the value `::fillme::` is considered blank, it does not have to be removed
# (let ((opt_short "::fillme::") (opt_long "::fillme::") (opt_arg "::fillme::")) (forward-line 2) (snip-insert "sh_b.opt-option" t t "sh" (concat " --key opt-minimal@opt-minimal-x@ --key skip_for_update --key opt_short --value " opt_short " --key opt_long --value " opt_long " --key opt_arg --value " opt_arg)))
# ||<-snap->|| define opt_option_templates
# ||<-snap->|| if !defined skip_for_update
# ||<-snap->|| default opt_option_update
# ||<-snap->|| if !defined skip_for_new
# ||<-snap->|| if eq have_opt yes
# ||<-snap->|| subst opt_option_update ## **CONDSIDER UPDATING THE OPTION GENERATOR TEMPLATE**
# ||<-snap->|| fi eq have_opt yes
# ||<-snap->|| fi !defined skip_for_new
@opt_option_update@
# ||<-snap->|| trim right
## (progn (forward-line 1) (snip-insert "sh_b.opt-option" t t "sh" " --key skip_for_update --key opt-minimal@opt-minimal-x@") (insert "\n"))
@opt_option_templates@
@opt_option_update@
# ||<-snap->|| trim right
# ||<-snap->|| fi !defined skip_for_update
# ||<-snap->|| if defined skip_for_update
# ||<-snap->|| if !defined skip_for_new
# ||<-snap->|| if !eq have_opt yes
@opt_option_templates@
# ||<-snap->|| fi !eq have_opt yes
# ||<-snap->|| fi !defined skip_for_new
# ||<-snap->|| fi defined skip_for_update
# ||<-snap->|| sh_b.opt-option
# ||<-snap->|| undef skip_for_update
# ||<-snap->|| subst skip_for_new
# ||<-snap->|| rem setup opt_long_case_patterns
# ||<-snap->|| define opt_long_case_patterns process
# ||<-snap->|| exec !process replace
python -c '
from __future__ import print_function
import sys;
for arg in sys.argv[1:]:
output = []
_indx = 3
while True:
output.append(arg[:_indx])
if not arg[_indx:]:
print("|".join(output))
break
_indx += 1
' '@dash_opt_long@@opt_long@'
# ||<-snap->|| exec
# ||<-snap->|| define opt_long_case_patterns
# ||<-snap->|| rem setup opt_arg
# ||<-snap->|| if eq opt_short @|empty@
# ||<-snap->|| if eq opt_long @|empty@
# ||<-snap->|| subst opt_arg
# ||<-snap->|| fi
# ||<-snap->|| fi
# ||<-snap->|| if defined opt_arg
# ||<-snap->|| if !eq opt_arg @|empty@
# ||<-snap->|| subst have_arg yes
# ||<-snap->|| subst opt_arg_sep @|space@
# ||<-snap->|| fi
# ||<-snap->|| fi
# ||<-snap->|| rem setup initial option value
# ||<-snap->|| if !defined opt_init
# ||<-snap->|| if eq have_arg yes
# ||<-snap->|| subst opt_init ''
# ||<-snap->|| else
# ||<-snap->|| subst opt_init @|empty@0
# ||<-snap->|| fi
# ||<-snap->|| fi
# ||<-snap->|| trim right
# ||<-snap->|| if eq have_opt yes
# ||<-snap->|| rem insert description, initialization, parser
# ||<-snap->|| rem # @dash_opt_short@@opt_short@@opt_short_long_comma@@dash_opt_long@@opt_long@@opt_arg_sep@@opt_arg_sep@@opt_arg@
# | @dash_opt_short@@opt_short@@opt_short_long_comma@@dash_opt_long@@opt_long@ |@opt_arg_sep@@opt_arg@ | ::fillme:: |@comm_activity@
opt_@opt_name@=@opt_init@
@dash_opt_short@@opt_short@@opt_short_long_bar@@opt_long_case_patterns@)@comm_opt@@opt_arg_sep@@opt_arg@
# ||<-snap->|| if eq have_arg yes
opt_@opt_name@="${2-}"
test x"${2+set}" != xset || shift@case_short_end@
# ||<-snap->|| opt-not-minimal
#pass_opts="${pass_opts}"' @pass_opt@ '"${opt_@opt_name@}"
#pass_opts="${pass_opts}"' @pass_opt@ '"$( single_quote_enclose "${opt_@opt_name@}" )"
@case_long_end@
# ||<-snap->|| opt-not-minimal
# ||<-snap->|| else
opt_@opt_name@=1@case_short_end@
# ||<-snap->|| opt-not-minimal
pass_opts="${pass_opts}"' @pass_opt@'
@case_long_end@
# ||<-snap->|| opt-not-minimal
# ||<-snap->|| fi
# ||<-snap->|| fi
# ||<-snap->|| sh_b.opt-option