# 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