#!/bin/bash
###############################################
#                                             #
#       ToriOS OS Menu Generator (JWM)        #
# copyright Israel<israeldahl@gmail.com> 2016 #
#               MIT License                   #
#                                             #
#      Prov 24:13 My son, eat thou honey,     #
#     because it is good; and the honeycomb,  #
#       which is sweet to thy taste:          #
# 14 So shall the knowledge of wisdom         #
# be unto thy soul: when thou hast found it,  #
#       then there shall be a reward,         #
#   and thy expectation shall not be cut off. #
#                                             #
#      Prose from KJV Bible public Domain     #
#                                             #
###############################################

## This file is HEAVILY COMMENTED
# It is meant to be an introduction to Bash shell script programming
# Please use an editor with syntax highlighting
# If you are new, I suggest using Geany, as it will allow you to jump to functions easily
## install geany via:
# sudo apt-get get install geany

##########################################################################################
##########################################################################################
##                                                                                      ##
##                                                                                      ##
## useful info [[ is a test function built in to bash                                   ##
## -z means Zero length... in other words is it empty?                                  ##
## -n means Not Zero length.. in other words, NOT empty                                 ##
## -f means File... is is a file?                                                       ##
## -d means Directory... is it a directory?                                             ##
## ALL bash variables start with $                                                      ##
## bash variables written like ${variableName} are wrapped in                           ##
## brackets { AND } to contain the words, if they are separated by spaces               ##
## (or a different internal field separator if you change it.. more on the $IFS later)  ##
##                                                                                      ##
##                                                                                      ##
##########################################################################################
##########################################################################################

## if jwm isn't installed we shouldn't run this anyway
# this test for a zero length string when looking for the path of jwm using the 'which' command
# if it is zero length it will exit
[[ -z "$(which jwm)" ]] && exit 1
menuFileToProcess=""
##shopt (shell options)
shopt -s nullglob
shopt -s globstar
## set up safer shellscript

#set -eC -o pipefail
# e if a command fails, exit
# u error on unset variables
# C disallow existing regular files to be overwritten by redirection of output

#setup our cache file directory
DIR="$HOME/.cache"
[[ -d "$DIR" ]] || mkdir -p "$DIR"
# name our cache file with the program name (argument 0 on the terminal)
## this variable subsitution removes everything before the /
## we need to 'escape' it by using \ because a / is used in substitution
progname="${0/*\/}"
MENUfileCACHE="$DIR/$progname.cache"

## setup our error log file
LOGDIR="$HOME/.jwm/jsm-logs"
[[ -d "$LOGDIR" ]] || mkdir -p "$LOGDIR"
LOGFILE="$LOGDIR/$progname.log"
[[ -f "$LOGFILE" ]] && rm "$LOGFILE"
date > "$LOGFILE"
## check if our cache file is a file, if so make sure everyone can read/write it in case this is run as root
[[ -f "$MENUfileCACHE" ]] && [[ "$(whoami)" == "root" ]] && chmod a+rw "$MENUfileCACHE" 2>>"$LOGFILE"
## this function will print the info to the screen and save it to a cache file
writeOut(){
  ## $* means ALL arguments sent in
  printf "%s\n" "$*" 2>>"$LOGFILE"
  printf "%s\n" "$*" >> "$MENUfileCACHE" 2>>"$LOGFILE"
}
## this function displays messages in XML format to not mess up the menu.
## run from a terminal to get the info anytime, but never notice it in the menu
## this function simply logs some sort of message to our LOG file
LOG(){
  MSG="$*"
  printf "%s\n" "${MSG}" >>"$LOGFILE"
}
outXML(){
  MSG="$*"
## the echo command is a bash built in, this prints a message to the standard output (usually the terminal)
# the result of an echo can be stored in a variable (more on this later)
# <!-- --> are the ways XML is commented
  writeOut "<!--$MSG-->"
  LOG "$MSG"
}

## this function makes strings compatible with XML format
quoteXML(){
  input="$*"
## two // in the variable substitute ALL occurances of the character, not just the first found
## the & symbol in xml is &amp;
  input="${input//&/&amp;}"
## the < is &lt;
  input="${input//</&lt;}"
## the > is &gt;
  input="${input//>/&gt;}"
## the " is &quot;
  input="${input//\"/&quot;}"
  printf "%s\n" "$input" 2>>"$LOGFILE"
}

#make a function to get the modification time
getModtime(){
  ## read that file sent in
  thisFile="$1"
  [[ ! -f "$thisFile" ]] && printf "%s\n" "$thisFile is not a file" 2>>"$LOGFILE" && return
  while read LINE || [[ -n "${LINE}" ]]
  do
  ## check the line for content using a case statement
    case $LINE in
      # does it contain Modify? this has the last modified time
      Modify*)printf "%s\n" "${LINE/Modify: }" 2>>"$LOGFILE"
      return;;
      *);;
    esac
  done < "$thisFile"  2>>"$LOGFILE"
}

#use stat to find the modificaion state of the apps directory and send it to a file
MODfile="$DIR/.appmod"
[[ -f "$MODfile" ]] && rm "$MODfile" 2>>"$LOGFILE"
stat /usr/share/applications/ > "$MODfile" 2>>"$LOGFILE"
[[ -f "$MODfile" ]] && [[ "$(whoami)" == "root" ]] && chmod a+rw "$MODfile" 2>>"$LOGFILE"
## get the time
currentMODtime=$(getModtime "$MODfile")
## check to see if we have done this before
if [[ -f "$MODfile.old" ]] && [[ -f "$MENUfileCACHE" ]]
then
  [[ "$(whoami)" == "root" ]] && chmod a+rw "$MODfile.old" 2>>"$LOGFILE"
  # get the old modification time
  getOLDmodTime=$(getModtime "$MODfile.old")
  ## if there has been no change simply wrte out our cache
  if [[ "$getOLDmodTime" == "$currentMODtime" ]]
  then
    LOG "The /usr/share/applications directory has not been modified recently"
    LOG "writing out the cache file ${MENUfileCACHE}"
## loop and echo out the file to the screen
    while read LINE || [[ -n "${LINE}" ]]
    do
       printf "%s\n" "${LINE}" 2>>"$LOGFILE"
    done < "${MENUfileCACHE}"  2>>"$LOGFILE"
## exit now so it is fast
    exit 0
  fi
fi
## store the current mod time in our .old file to compare next time.
mv "$MODfile" "$MODfile.old"  2>>"$LOGFILE"
[[ -f "${MENUfileCACHE}" ]] && rm "${MENUfileCACHE}" 2>>"$LOGFILE"
## if there is no file sent in, lets use our default
[[ -z "$menuFileToProcess" ]] && menuFileToProcess="jwm-applications.menu"
LOG "$menuFileToProcess"
## default icon
DEFAULT_ICON="application-default-icon"
myLANG=""
##this is used for localization
[[ -n "$myLANG" ]] || myLANG="${LANGUAGE%% *}"
[[ -n "$myLANG" ]] || myLANG="${LANG%_*}"
LOG "Language: $myLANG"
LIST_FILE="$HOME/.applist"
[[ -f "$LIST_FILE" ]] && rm "$LIST_FILE" 2>>"$LOGFILE"


## This is a function.
## functions can be written as
# function xdgConfigFilePATH{
# OR
# xdgConfigFilePATH(){
# the second method is more similar to other languages, and that is what I use here
## This checks for a FILE in the XDG_CONFIG_DIRS path (or /etc/xdg if the variable is unset)
xdgConfigFilePATH(){
  ## Store the First argument in our variable named FILE
  FILE="$1"
  local IFS=":"
  ## The IFS is a special variable
  # IFS is what separates an array into individual items
  # the normal IFS is a space character ' '
  # we change it to a colon ':' here because the variable is separated by colons
  # FOR EXAMPLE:
# OUR variable contains   /etc/xdg/xdg-torios:/etc/xdg
# we make an array that ends up acting like
# ARRAY position 1 = /etc/xdg/xdg-torios
# ARRAY position 2 = /etc/xdg
# we loop through this variable using a 'for' loop
## WE use another built in for variables
# ${XDG_CONFIG_DIRS:-/etc/xdg}
## the important part to learn is :-/etc/xdg}
## this means if the environment variable $XDG_CONFIG_DIRS is empty we will automatically use /etc/xdg as the value
  for i in ${XDG_CONFIG_DIRS:-/etc/xdg}
  do
# do is the actual looping command... everything between 'do' and 'done' is run each time
# i is a variable that is usually used to iterate over loops in MANY programming languages.  this stems back to when writing programs was more comlpicated, using shorter names like 'i' instead of 'iterator' was more sensible.
# now it is just a tradiational practice

## this checks to see if the FILE we sent in is a file in the directory in our array
    if [[ -f "${i%/}/$FILE" ]]
    then
       ## it IS, so lets combine the variables into a filename
       FILEname="${i%/}/$FILE"
       ## this will send the filename OUT of this function
       printf "%s\n" "$FILEname" 2>>"$LOGFILE"
       LOG "Filename=$FILEname"
       ## this will end the function and not check the other directories
       return
     # all if statements end in 'fi'  this is the way the program knows the test is over
     fi
  done  2>>"$LOGFILE"
}
## This checks for a DIRECTORY in the XDG_DATA_DIRS path (or /usr/share if the variable is unset)
# read the above function xdgConfigFilePATH() for more info one how this all works
dataPATH(){
  DIR="$1"
  local IFS=":"
  for i in ${XDG_DATA_DIRS:-/usr/share}
  do
## check if this is a directory
    if [[ -d "${i%/}/$DIR" ]]
    then
       DIRECTORY="${i%/}/$DIR"
       printf "%s\n"  "$DIRECTORY" 2>>"$LOGFILE"
       LOG "XDG data directory: $DIRECTORY"
     fi
  done  2>>"$LOGFILE"
}

## This checks for a FILE in the XDG_DATA_DIRS path (or /usr/share if the variable is unset)
# read the above function xdgConfigFilePATH() for more info one how this all works
filePATH(){
  FILE="$1"
  local IFS=":"
  for i in ${XDG_DATA_DIRS:-/usr/share}
  do
    if [[ -f "${i%/}/$FILE" ]]
    then
       FILENAME="${i%/}/$FILE"
       printf "%s\n"  "$FILENAME" 2>>"$LOGFILE"
       return
     fi
  done  2>>"$LOGFILE"
}

processMenuStart(){
  menuFile="$1"
  [[ -z "$menuFile" ]] && return
## this looks in the menu file (the *.directory file we sent in) line by line
  while read LINE || [[ -n "$LINE" ]]
  do
## a case statement looks at a variable and checks for conditions that match it
    case $LINE in
## does ths line contain Name=
## it gets the line with the localized name (or just the name)
## "${LINE#*=}" This will REMOVE everything before the '='
      Name?${myLANG%_*}?=*|Name=*) NAME="${LINE#*=}"'';;
 ## EVERY SECTION MUST END IN ;;

## then it gets the Icon
      Icon=*) ICON="${LINE#*=}"''  ;;
 ## EVERY SECTION MUST END IN ;;
 ## EVERY SECTION MUST END IN ;; (just in case you missed me saying this earlier)
    ## just like 'if' statements end in 'fi' 'case' statements end in 'esac'
    esac
## this pipes the file into our loop to be read line by line
  done < "$menuFile" 2>>"$LOGFILE"
## if the file is the 'other' category file export the Name
## it checks to see if removing the word 'other' from the filename
# makes the filename different...
# if so, then it must be the 'other' file
  if [[ "${menuFile/other}" !=  "$menuFile" ]]
  then
    OTHER_NAME="$NAME"
    [[ -n "$DEBUGMENU" ]] && outXML "Other category is = $OTHER_NAME"
    export OTHER_NAME
  fi
## if it is a chrome file, export the name
# see the 'other' above to see how this works
  if [[ "${menuFile/chrome}" !=  "$menuFile" ]]
  then
    CHROME_NAME="$NAME"
    [[ -n "$DEBUGMENU" ]] && outXML "Chrome category is = $CHROME_NAME"
    export CHROME_NAME
  fi
## if nothing is blank, send out a JWM menu start
  [[ -n "$NAME" ]] && writeOut "    <Menu label=\"$(quoteXML ${NAME})\" icon=\"$(quoteXML ${ICON:-$DEFAULT_ICON})\" height=\"0\">"
}

## this is a function that calls another function... I just set it up to make it less error prone than retyping the directory name any time I need it
desktopDIRECTORYPATH(){
  dataPATH "desktop-directories"
}
applicationsDIR(){
  dataPATH "applications"
}

listDESKTOPfiles(){
## this gets the applications directory
  apps_DIR=($(applicationsDIR))
## this makes an array of all the desktop files in this direcory
  for currdir in "${apps_DIR[@]}"
  do
    for desktopfile in "$currdir"/**.desktop
    do
    #  if it is a file, add it to our list of files
      [[ -f "$desktopfile" ]] && printf "%s\n" "$desktopfile">>"$LIST_FILE" 2>>"$LOGFILE"
    done  2>>"$LOGFILE"
  done
## check the local applications directoryusing a default if the variable is empty see comments in xdgConfigFilePATH() for more info
  for i in "${XDG_DATA_HOME:-$HOME/.local/share/}applications"/**.desktop
  do
    [[ -f "$i" ]] && printf "%s\n" "$i">>"$LIST_FILE" 2>>"$LOGFILE"
  done  2>>"$LOGFILE"

}
## this runs the above function
listDESKTOPfiles

## this is where our category name localizations exist, and the icon names for the categries
# this runs the function and stores the output in this variable
desktop_DIRECTORY=($(desktopDIRECTORYPATH))

PROCESS_category(){
  CAT="$1"
## just as $1 is the FIRST argument sent into a function, $2 is the second.
  CATLIST="$2"
## see xdgConfigFilePATH for info on IFS
  IFS=";"
  for category in ${CATLIST}
  do
## two = signs COMPARE variables.
# one = sign sets a variable
## this checks if the value of the variable "$category" is the same as the value of the variable "$CAT"
    if [[ "$category" == "$CAT" ]]
    then
      [[ -n "$DEBUGMENU" ]] && LOG "Category: $category"
      printf "%s\n" "$category"  2>>"$LOGFILE"
    fi
  done  2>>"$LOGFILE"
}

checkENV(){
  LIST="$1"
## see xdgConfigFilePATH for info on IFS
  IFS=";"
  for envVAR in ${LIST}
  do
## this is the shorter form of the same thing in PROCESS_category function above
## if they are equal echo it out
    [[ "$envVAR" == "${XDG_CURRENT_DESKTOP:-JWM}" ]] && printf "%s\n" "$envVAR" 2>>"$LOGFILE"
  done 2>>"$LOGFILE"
}


checkDESKTOPfile(){
  CAT="$1"
  while read DESKTOP_FILE || [[ -n "$DESKTOP_FILE" ]]
  do
## these variables must be rest after each file is checked, otherwise we might get funny names/variables/etc...
    NAME=""
    ICON=""
    CATS=""
    EXEC=""
    TERMIE=""
    COMMENT=""
    MenuEntry=""
    NO=""
## lets make sure it is a file before trying to read it
    if [[ -f "$DESKTOP_FILE" ]]
    then
    [[ -n "$DEBUGMENU" ]] && outXML "Checking desktop file: $DESKTOP_FILE"
## read each line
    while read LINE || [[ -n "$LINE" ]]
    do
## see processMenuStart() for more info on case statements
## look at some desktop files to get an understanding of what this is doing.
## it is fairly straight forward
    case $LINE in
        "NoDisplay=true")
## reset all variables if the file is not supposed to be displayed
           NAME=""
           ICON=""
           CATS=""
           EXEC=""
           TERMIE=""
           COMMENT=""
          break;;
        Name?${myLANG%_*}?=*|Name=*) NAME="${LINE#*=}"''
        ## this will look for a localized name first, or the generic name if it isn't found
;;
        '[Desktop Entry'*) continue ;;
        TryExec=*|Exec=*) EXEC="${LINE#*=}"'' ;;
        Icon=*) ICON="${LINE#*=}"''  ;;
        Terminal=*) TERMIE="${LINE#*=}"'';;
        "["*) break ;;
        OnlyShowIn=*)
          tester="${LINE#*=}"''
          if [[ -z $(checkENV "$tester") ]]
          then
## a zero length result of the function checkENV means we DON'T want to show this
## if we aren't using it reset the variables so they don't carry over on accident to the next file
           NAME=""
           ICON=""
           CATS=""
           EXEC=""
           TERMIE=""
           COMMENT=""
           NO="TRUE"
          fi
          break;;
        NotShowIn=*)
          tester="${LINE#*=}"''
          if [[ -n $(checkENV "$tester") ]]
          then
## a NON zero length result of the function checkENV means we WANT to show this
## if we aren't using it reset the variables so they don't carry over on accident to the next file
           NAME=""
           ICON=""
           CATS=""
           EXEC=""
           TERMIE=""
           COMMENT=""
           NO="TRUE"
          fi
          break;;
        Comment=*|Comment?${LANG%_*}?=*) COMMENT="${LINE#*=}"'';;
        Categories=*)
          CATS="${LINE#*=}"''
          [[ -z "$CATS" ]] && [[ "${DESKTOP_FILE/chrome-}" != "$DESKTOP_FILE" ]] && CATS="$CHROME_NAME"
          [[ -z "$CATS" ]] && CATS="Other"
          if [[ -z $(PROCESS_category "$CAT" "$CATS") ]]&& [[ "${DESKTOP_FILE/chrome-}" == "$DESKTOP_FILE" ]] && [[ "$CATS" != "Other" ]]
          then
## reset if this file is something we shouldn't make an entry for
# basically if this is an 'Other' file we don't want to include it unless the category sent in to this function to make is actually 'Other'
            NAME=""
            ICON=""
            CATS=""
            EXEC=""
            TERMIE=""
            COMMENT=""
            #break
            #return
          fi
          ;;
         *);;
    esac
    done < "$DESKTOP_FILE"  2>>"$LOGFILE"

    if [[ -n "$EXEC" ]] && [[ -n "$NAME" ]] && [[ -n "$CATS" ]] && [[ -z "$NO" ]]
    then
## this uses the program sed to remove the desktop file we processed from our list file
      [[ -f "$LIST_FILE" ]] && sed -i "s#$DESKTOP_FILE##" "$LIST_FILE" 2>>"$LOGFILE"
      if [ "${TERMIE}" == "true" ]
      then
        [[ -n "$(which xterm 2>>$LOGFILE)" ]] && EXEC="xterm -e ${EXEC}"
        [[ -n "$(which x-terminal-emulator 2>>$LOGFILE)" ]] && EXEC="x-terminal-emulator -e ${EXEC}"
      fi
      [[ -z "${ICON}" ]] && ICON="${DEFAULT_ICON}"
      executable=${EXEC%\ \%?}
      if [[ -z "$COMMENT" ]]
      then
## quoteXML changes all '&' symbols to '&amp;' etc... for correct XML formatting...  this menu wont work if we don't convert all '&' (etc..) to correct XML format
        MenuEntry="        <Program label=\"$(quoteXML ${NAME})\" icon=\"$(quoteXML ${ICON})\">$(quoteXML ${executable})</Program>"
      else
        MenuEntry="        <Program label=\"$(quoteXML ${NAME})\" tooltip=\"$(quoteXML ${COMMENT})\" icon=\"$(quoteXML ${ICON})\">$(quoteXML ${executable})</Program>"
      fi
## this just makes the formatting pretty
## we we don't already have something in the menu, make it on a signle line
## if we have something make it on a new line
      if [[ -z "$MENU" ]]
      then
        MENU="$MenuEntry"
      else
        MENU="$MENU
$MenuEntry"
      fi
   fi
   fi
   unset NO
done < "$LIST_FILE" 2>>"$LOGFILE"
  ## echo will print this out for storage in a variable
##makeThings() stores this in a variable named CATIE
  printf "%s\n" "$MENU" 2>>"$LOGFILE"
  MENU=""
}

removeTAGS(){
  LINE="$1"
## this removes all the tags from a line
## for example <Directory>jwm-office.directory</Directory>
## will become jwm-office.directory
  tagless="${LINE/<\/*}"
  tagless="${tagless/*>}"
  printf "%s\n" "$tagless" 2>>"$LOGFILE"
}

checkFILE(){
  thisfilename="$1"
  DIR="${XDG_DATA_HOME:-$HOME/.local/share}"
  [[ -f "${DIR%/}/desktop-directories/$thisfilename" ]] && printf "%s\n" "${DIR%/}/desktop-directories/$thisfilename" 2>>"$LOGFILE" && return
  for dir in  "${desktop_DIRECTORY[@]}"
  do
    [[ -f "$dir/$thisfilename" ]] && printf "%s\n" "$dir/$thisfilename" 2>>"$LOGFILE" && return
  done
  [[ -f "$thisfilename" ]] && printf "%s\n" "$thisfilename" 2>>"$LOGFILE" && return
}

makeThings(){
  DIRECTORYFILE="$1"
  if [[ -z "$DIRECTORYFILE" ]] || [[ -z "${CATEGORIES[*]}" ]]
  then
     outXML "$DIRECTORYFILE::wont work::${CATEGORIES[*]}"
  fi
  for category in "${CATEGORIES[@]}"
  do
    if [[ ${DIRECTORYFILE/application} == "$DIRECTORYFILE" ]]
    then
      thisCAT="$category"
      [[ -n "$DEBUGMENU" ]] && outXML "$thisCAT"
      CATIE=$(checkDESKTOPfile "$thisCAT")
      if [[ -n "$CATIE" ]]
      then
        [[ -n "$DEBUGMENU" ]] && outXML "$DIRECTORYFILE"
        processMenuStart "$DIRECTORYFILE"
        writeOut "$CATIE"
        writeOut "    </Menu>"
      fi
    fi
  done
}
processMenuFile(){

## this process the xdg menu file
## see previous while read LINE
## also see previous case statements for more info
  filename="$1"
  filename=$(xdgConfigFilePATH "menus/$filename")
  OIFS="$IFS"
  while read LINE || [[ -n "$LINE" ]]
  do
    TAGLESS=""
    case $LINE in
        *"<Include>"*)
          include="true"
        ;;
        *"<Not>"*)
          NOT="true"
        ;;
        *"</Not>"*)
          unset NOT
        ;;
		*"<Menu>"*)
## this is a holder so I can see the xml depth.
# it is either the first one, or a sub element
          if [[ -z "$MAIN" ]]
          then
             MAIN="true"
          else
             SUB="true"
          fi
        ;;
       *"<Directory>"*)
          if [[ -n "$MAIN" ]] && [[ -n "$SUB" ]]
          then
            TAGLESS=$(removeTAGS "$LINE")
            TAGLESS=$(checkFILE "$TAGLESS")
            IFS=":"
            FILELIST=( ${FILELIST[@]} "$TAGLESS")
            DIRECTORY="$TAGLESS"
          fi
        ;;
        *"<Category>"*)
          if [[ -z "$Einclude" ]] && [[ -z "$ENOT" ]]
          then
            TAGLESS=$(removeTAGS "$LINE")
            CATEGORIES=(${CATEGORIES[@]} "$TAGLESS")
            export CATEGORIES
          fi
        ;;
        *"</Include>"*)
          makeThings "$DIRECTORY"
## unset makes a variable zero length... in other words it empties it and makes the variable nothing
          unset DIRECTORY
          unset CATEGORIES
          unset include
        ;;
        *"</Menu>"*)
            if [[ -n "$SUB" ]]
            then
## this will empty the SUB variable so I know that we have finished an entire XML element
              unset SUB
            elif [[ -n "$MAIN" ]] && [[ -z "$SUB" ]]
            then
              break
            fi
        ;;
        *);;
    esac
  done < "$filename" 2>>"$LOGFILE"

}
locality(){
  localDIR="${XDG_DATA_HOME:-$HOME/.local/share}"
  IFS=":"
  for localfile in "${localDIR%/}/desktop-directories/"**.directory
  do
    LOCALfile=$(checkFILE "$localfile")
    if [[ -f "$LOCALfile" ]]
    then
      LOG "Local file: $LOCALfile"
      FILELIST=(${FILELIST[@]} "$LOCALfile")
      while read numero || [[ -n "$numero" ]]
      do
        case $numero in
           Name=*)RES="${numero/*=}";;
           *);;
        esac
      done <"$LOCALfile" 2>>"$LOGFILE"
      CATEGORIES=(${CATEGORIES[@]} "$RES")
      export CATEGORIES
      makeThings "$LOCALfile"
    fi
  done 2>>"$LOGFILE"
  #unset CATEGORIES
}
makeTheMenu(){
  ## echo out the XML and JWM header
  printf "%s\n" "<JWM>" > "$MENUfileCACHE" 2>>"$LOGFILE"
    [[ -n "$DEBUGMENU" ]] && printf "%s\n" "<!-- generated by $0 -->" > "$MENUfileCACHE" 2>>"$LOGFILE"
  printf "%s\n" "<JWM>" 2>>"$LOGFILE"
    [[ -n "$DEBUGMENU" ]] && printf "%s\n" "<!-- generated by $0 -->" 2>>"$LOGFILE"
  ## run the local file part
  locality
  ## process the menufile sent in, (or use our default we set in the beginning
  processMenuFile "$menuFileToProcess"
  ## echo out the ending tag
  writeOut "</JWM>"
  ## if our list file exists, remove it to clean up!
}
## this is the help screen we show
usage(){
  printf "%s\n" "${0} [OPTIONS]"
  printf "\n"
  printf "%s\n" "  -d|--debug|-v|--verbose  turn on verbose debug logging to $LOGFILE"
  printf "%s\n" "  -h|-\?|--help"
  printf "%s\n" "  -f|--file|-file|--filename [FILENAME]"
  printf "%s\n" "  --filename=[FILENAME]"
}
## this will loop through all the arguments sent into the program
while :
do
  case $1 in
    -d|--debug|--debug|-v|--verbose)DEBUGMENU="true";;
    -h|-\?|--help) usage;;
    -f|--file|-file|--filename)
       menuFileToProcess="$2"
       shift
       ;;
    --filename=*) menuFileToProcess="${1/*=}" ;;
    --)
      shift
      break
      ;;
    *)break;;
  esac
  shift
done
## run the function makeTheMenu() to generate the menu
makeTheMenu
[[ -f "$LIST_FILE" ]] && rm "$LIST_FILE" 2>>"$LOGFILE"
[[ "$(whoami)" == "root" ]] && chmod a+rw "$LOGFILE" 2>>"$LOGFILE"
#cat "$MENUfileCACHE"
