summaryrefslogtreecommitdiffstats
path: root/examples/simple_menu/simple_menu.sh
diff options
context:
space:
mode:
Diffstat (limited to 'examples/simple_menu/simple_menu.sh')
-rwxr-xr-xexamples/simple_menu/simple_menu.sh220
1 files changed, 220 insertions, 0 deletions
diff --git a/examples/simple_menu/simple_menu.sh b/examples/simple_menu/simple_menu.sh
new file mode 100755
index 0000000..2092478
--- /dev/null
+++ b/examples/simple_menu/simple_menu.sh
@@ -0,0 +1,220 @@
+#/bin/bash
+
+# Variables
+# """""""""
+PROG=${0#*/}
+
+typeset -a MENU_STACK # A stack of MENUS to store the previously visited menus
+
+# Array of menu characteristics for caching purpose
+# '''''''''''''''''''''''''''''''''''''''''''''''''
+typeset -A MENU_ARRAY
+typeset -A COL_ARRAY
+typeset -A CENTERING_ARRAY
+typeset -A TITLE_ARRAY
+typeset -A ERASE_ARRAY
+
+SEL= # The selection
+
+# ============================ #
+# Usage function, always fails #
+# ============================ #
+function usage
+{
+ echo "Usage: $PROG menu_file[.mnu] user_program," >&2
+ echo " read the README for an example" >&2
+ exit 1
+}
+
+# ==================== #
+# Fatal error function #
+# ==================== #
+function error
+{
+ echo $* >&2
+ exit 1
+}
+
+# The script expects exactly one argument (the filename of the root menu).
+# """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+(( $# != 2 )) && usage
+
+USER_PROGRAM=$2
+
+# ======================================================================= #
+# Parse a level in the menu hierarchy and call process with the selection #
+# (possibly empty). #
+# ======================================================================= #
+function process_menu
+{
+ TITLE="[ENTER: select, q: abort]"$'\n' # Untitled by default
+ CENTERING= # Is the menu centered in the screen ?
+ ERASE= # Destroy the selection window after use
+
+ MENU_FILE=$1
+ MENU= # Make sure the working area is empty
+
+ # If the menu has already been seen, read its characteristics from the cache
+ # else construct them.
+ # """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+ if [[ -z ${MENU_ARRAY[$MENU_FILE]} ]]; then
+ COL=1
+
+ # Parse the directives embedded in the menu file
+ # """"""""""""""""""""""""""""""""""""""""""""""
+ MENU_DIRECIVES=$(grep '^\.' $MENU_FILE)
+
+ while read DIRECTIVE VALUE; do
+ case $DIRECTIVE in
+ .columns) # Number of columns of the menu
+ COL=$VALUE
+ (( COL < 1 || COL > 15 )) && error "$DIRECTIVE, bad value"
+ ;;
+
+ .centered) # Is the menu centered?
+ [[ $VALUE == yes ]] && CENTERING="-M"
+ ;;
+
+ .eraseafter) # Will the space used by the menu be reclaimed?
+ [[ $VALUE == yes ]] && ERASE="-d"
+ ;;
+
+ .title) # The menu title
+ TITLE="$VALUE"$'\n'$TITLE
+ ;;
+
+ *)
+ error "bad directive $DIRECTIVE"
+ ;;
+ esac
+ done <<< "$MENU_DIRECIVES"
+
+ # Build the menu entries in the working area
+ # """"""""""""""""""""""""""""""""""""""""""
+ MENU_LINES=$(grep -v -e '^\.' -e '^#' -e '^[ \t]*$' $MENU_FILE)
+
+ # The special tag "---" creates an empty entry (a hole in a column)
+ # The special tag "===" create an empty line
+ # The special tag "EXIT" permit to exit the menu
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+ while read TAG VALUE; do
+ ITEMS_TO_ADD=1 # By default, only one iteration of the tag is taken
+ # into account
+
+ (( ${#TAG} > 10 )) && error "Menu tag too long (max 10 characters)."
+
+ [[ $TAG == --- ]] && VALUE=@@@
+ [[ $TAG == === ]] && VALUE=@@@ && ITEMS_TO_ADD=COL
+
+ [[ -z $VALUE ]] && error "Empty menu entry for $TAG"
+ [[ $TAG == EXIT ]] && TAG="@EXIT@xxxx00"
+ [[ $TAG == "<"* ]] && TAG="<xxxxxxxxx00"
+
+ # Protect quotes in VALUE
+ # """""""""""""""""""""""
+ FINAL_VALUE=$(echo "$VALUE" | sed -e 's/"/\\"/' -e "s/'/\\\\'/")
+
+ while (( ITEMS_TO_ADD-- > 0 )); do
+ MENU+="'$TAG $FINAL_VALUE'"$'\n'
+ done
+ done <<< "$MENU_LINES"
+
+ # Feed the cache
+ # """"""""""""""
+ MENU_ARRAY[$MENU_FILE]="$MENU"
+ COL_ARRAY[$MENU_FILE]=$COL
+ CENTERING_ARRAY[$MENU_FILE]=$CENTERING
+ TITLE_ARRAY[$MENU_FILE]=$TITLE
+ ERASE_ARRAY[$MENU_FILE]=$ERASE
+ else
+ # Read from the cache
+ # """""""""""""""""""
+ MENU="${MENU_ARRAY[$MENU_FILE]}"
+ COL=${COL_ARRAY[$MENU_FILE]}
+ CENTERING=${CENTERING_ARRAY[$MENU_FILE]}
+ TITLE=${TITLE_ARRAY[$MENU_FILE]}
+ ERASE=${ERASE_ARRAY[$MENU_FILE]}
+ fi
+
+ # Display the menu and get the selection
+ # """"""""""""""""""""""""""""""""""""""
+ SEL=$(echo "$MENU" | ../../smenu \
+ $CENTERING \
+ $ERASE \
+ -N \
+ -F -D o:10 i:0 n:2 \
+ -n \
+ -m "$TITLE" \
+ -t $COL \
+ -S'/@@@/ /' \
+ -S'/^[^ ]+ //v' \
+ -e @@@)
+ SEL=${SEL%% *}
+}
+
+# Check for the presence of ../../smenu
+# """""""""""""""""""""""""""""""""""""
+[[ -x ../../smenu ]] || error "smenu is not there, please build it."
+
+# Initialize the menu stack with the argument
+# """""""""""""""""""""""""""""""""""""""""""
+MENU_STACK+=(${1%.mnu}.mnu)
+
+# And process the main menu
+# """""""""""""""""""""""""
+process_menu ${1%.mnu}.mnu
+
+# According to the selection, navigate in the submenus or return
+# the tag associated with the selected menu entry.
+# """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+while true; do
+ if [[ $SEL == "<"* ]]; then
+ # Back to the previous menu
+ # '''''''''''''''''''''''''
+ if (( ${#MENU_STACK[*]} == 1 )); then
+ process_menu ${MENU_STACK[-1]}
+ else
+ # Unstack the newly found submenu
+ # '''''''''''''''''''''''''''''''
+ unset MENU_STACK[-1]
+
+ # And generate the previous menu
+ # ''''''''''''''''''''''''''''''
+ process_menu ${MENU_STACK[-1]}
+ fi
+
+ elif [[ $SEL == ">"* ]]; then
+ # Enter the selected submenu
+ # ''''''''''''''''''''''''''
+ SMENU_FILE=${SEL#>}
+ SMENU_FILE=${SMENU_FILE%.mnu}.mnu
+ [[ -f $SMENU_FILE ]] || error "The file $SMENU_FILE was not found/readable."
+
+ # Stack the newly found submenu
+ # '''''''''''''''''''''''''''''
+ MENU_STACK+=($SMENU_FILE)
+
+ # And generate the submenu
+ # ''''''''''''''''''''''''
+ process_menu $SMENU_FILE
+ else
+ # An empty selection means than q or ^C has been hit
+ # ''''''''''''''''''''''''''''''''''''''''''''''''''
+ [[ -z $SEL ]] && exit 0
+
+ # Output the selected menu tag or exit the menu without outputting
+ # anything.
+ # ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+ [[ $SEL == @EXIT@* ]] && exit 0
+
+ # Lauch the user action which has the responsibility to act according
+ # to the tag passed as argument.
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+ $USER_PROGRAM $SEL
+
+ # And re-generate the current menu
+ # ''''''''''''''''''''''''''''''''
+ process_menu ${MENU_STACK[-1]}
+ fi
+done