# Welcome to bbmenu.sh. This file defines two functions: bbmenu and bbconfmenu.
# bbmenu is used to define a common menu system for bashburn.
# bbconfmenu is used to define both the regular Configure and
# the Advanced Configure menu. They are fundamentally different because bbmenu
# creates menus that are composed of an item and a function that gets executed
# if it is selected.
# bbconfmenu displays menus that show a configuration parameter and
# a current value. If an item is selected then a third param explains what
# config param is. A fourth parameter is allowed to be
# executed which can help the user to understand what values are best selected.
#
# One of the arguments to these functions has to be the name of a menu
# which must be a global-scope array.
# In the case of bbmenu the menu definition array must be a 2-tuple of the name
# to be displayed for the menu item, and the function to be invoked if the item
# is selected.
# ALL ITEMS ARE SEPERATED BY AMPERSAND.
# In the case of bbconfmenu, the array elements are a 4-tuple, composed of:
# * The name of the menuitem
# * The name of the configuration parameter to be affected.
# * The prompt to be displayed if the user selects a parameter to be modified.
# * An optional string to be eval'd.
#
# A complexity that is part of these menus is that the language that
# gets displays is subject to change if the user tries to reconfigure BBLANG.
# This impacts not only the configure menu that the change occurs from, but
# also the main menu that the configure menu is called from. So the goal is
# that the Configure menu has to display things in the newly selected language
# and its caller has to change the language that it was running in after
# the Configure menu has returned.
print_hdr()
{
# print a uniform header.
typeset title="$1"
clear
#
echo -e "${BBTABLECOLOR}${BBDECOLINE}
${BBTABLECOLOR}|${BBHEADCOLOR} ${BBVERSION} ${BBTABLECOLOR}|
${BBTABLECOLOR}${BBDECOLINE}
${BBTABLECOLOR}|
${BBTABLECOLOR}|-(${BBSUBCOLOR}$title${BBTABLECOLOR})"
}
bbmenu()
{
# This is the common memu used by bb.
# THERE BE DRAGONS HERE. Test well if you modify it.
# BE CAREFUL with your quoting. If you think you're right then test
# it and check the bash man page again.
typeset old_IFS="$IFS" # Save IFS. Which one are we saving?
# Wrong answer! We're saving the global copy.
typeset IFS="$IFS" # NOW we're creating a local copy and
# initializing it with the global value.
typeset titlename="$1" # Pull off the title from the arglist.
typeset menuname="$2"
shift
typeset -a item # Convenience variables after parse.
typeset -a action
typeset -i ii=0 # Loop index
typeset jj
typeset -i size # Nr of menu items
typeset -a descriptors # We need to save the arglist because set will
# override them.
typeset -r protofmt='%b|%b %2d) %s%b'
typeset nl # Might be a newline or it might not...
# The last %b is either "\n" or ""
typeset chselection # Set by read
typeset selection # User's real choice.
typeset prompt
typeset -i nogood=0
set_descriptors()
{
size=$(eval "echo \"\${#$menuname[@]}\"" )
for (( ii=0; ii= size )) && nl= || nl="\n"
printf "$protofmt" ${BBTABLECOLOR} ${BBMAINCOLOR} \
$ii "${item[ii]}" "$nl"
done
# Why are we doing this instead of using the prompt functionality
# of read? Because read won't display escape sequences.
# It only knows how many characters it printed, not how many
# were printable.
prompt=$(printf "\n%b|
%b$bb_menu_input[0-$((size-1))] |>%b " \
${BBTABLECOLOR} ${BBINPUTCOLOR} ${BBMAINCOLOR})
read -e -p "$prompt" chselection # Get the user's choice.
# look up which action is associated with the choice.
# if just enter is pressed, ignore it...
# (there must be a better way to do this).
nogood=0
if [[ -n "$chselection" ]]
then
# Assign chselection to selection. But selection is an integer
# variable and chselection is not. If chselection is not numeric
# then the value of selection will be zero.
# SO, to see if the luser boned us, we assign and see if selection
# if 0 and chselection is not.
# Then after that we do the standard test to see if the number
# is in bounds.
# Remove non-DIGITS from real selection
selection="${chselection//[^0-9]/}"
if [[ "$selection" != "$chselection" ]]
then
nogood=1
elif (( selection >= 0 && selection < size ))
then
eval ${action[selection]} # Do it.
else
nogood=1
fi
if (( nogood == 1 ))
then
top_info_line
message "$bb_menu_error_range ${BBHEADCOLOR}$bb_exit_err [0-$(( size - 1 ))]${BBCOLOROFF}\n"
fi
fi
done
} # bbmenu
bbconfmenu()
{
# If you thought the previous code was tricky then don't even look at this.
# It'll make your brain explode.
typeset old_IFS="$IFS" # Save IFS. Which one are we saving?
# Wrong answer! We're saving the global copy.
typeset IFS="$IFS" # NOW we're creating a local copy and
# initializing it with the global value.
# 1st 4 args are the actions to be taken for the four actions at the end.
# (whatever they are ;-)
typeset menuname="${1}" # Name of the array that's passed in.
typeset toptext1name=$2
typeset toptext2name=$3
typeset size1action="$4"
typeset size2action="$5"
typeset size3action="$6"
typeset size4action="$7"
typeset toptext1
typeset toptext2
shift 7
typeset -a descriptors # All the rest of the menu conf values.
typeset -i size # The number of entries in descriptors
typeset -i size1 # size + 1
typeset -i size2
typeset -i size3
typeset -a var # List of all of the config variables.
typeset lvar # Basically it's var[i] with indirection
# It's to solve a bash limitation with arrays.
typeset lval # Same trick in a different context.
typeset -a text # Array of variable descriptions.
typeset -i jj=0 # Used to index into indirect of CFG_CHANGES
typeset -i ii=0 # General array index
typeset star # Set to either an asterick or null to
# indicate that a value is modified.
typeset dispval # If star is set that dispval will be displayed
# instead of the actual value of the
# config parameter.
typeset changed_var # Name of the changed variable.
typeset newval # New value to be applied to changed variable.
typeset action # read var for user's choice.
typeset -i act # interger version of action.
typeset -a change_prompt # List of prompts on what the user
# is selecting to change.
typeset -a info_cmd # command to be executed (optional) for changing.
typeset -ai strict_enum # Define if the user is allowed to specify
# from a list of made up values.
typeset -i cfgsize=0 # Size of the number of outstanding changes.
typeset prompt # readline prompt string in living color.
typeset -a menu_extras # Last *4* (ooops) entries.
# I don't get why it can't be inited at decl. :-(
typeset -a menu_extras_names
# Now here's somthing you don't see everyday Bullwinkle.
# What's that Rocky?
# A function defined in a shell script that's nested!
# You're right Rocky. But that'll never work. How can set_descriptors see
# the variable menuname?
# That's why it *does* work. Because it's nested.
set_descriptors()
{
size=$(eval "echo \"\${#$menuname[@]}\"" )
for (( ii=0; ii %b " \
${BBINPUTCOLOR} ${BBMAINCOLOR})
read -e -p "$prompt" action
echo -e "${BBCOLOROFF}"
# If the action is in range of the descriptor table then
# we process it with change_option.
act="${action//[^0-9]/}"
if [[ "$action" != "$act" ]]
then
top_info_line
message "$bb_menu_error_range ${BBHEADCOLOR}$bb_exit_err [0-$((size+3))]${BBCOLOROFF}\n"
elif (( action < size ))
then
change_option \
"${var[act]}" \
"${change_prompt[act]}" \
"${info_cmd[act]}" \
${strict_enum[act]}
elif (( action < size + "${#menu_extras[@]}" ))
then
# Otherwise we have custom actions that were passed in.
# NOTE: None of this works if the sizes are not declared int.
size1=size+1
size2=size+2
size3=size+3
case $action in
$size)
eval $size1action
;;
$size1)
eval $size2action
;;
$size2)
eval $size3action
;;
$size3)
eval $size4action
;;
esac
else
top_info_line
message "$bb_menu_error_range ${BBHEADCOLOR}$bb_exit_err [0-$((size+3))]${BBCOLOROFF}\n"
fi
done
} # bbmenuconf