#!/bin/bash
#---------------------------------------------------------------------
## @Synopsis gaze - view sorcery spell management information
## (gaze into the crystal ball)
## @Copyright First version of gaze written & copyrighted 2001 by Brian Peterson
## @Copyright Current version contains none of Brian Peterson's code and is Copyright 2001 by Kyle Sallee
## @Copyright Other additions/corrections Copyright 2002 by the Source Mage Team
#---------------------------------------------------------------------


function help() {
cat << EOF

Invoke gaze with desired command followed by arguments.
Please note that anything in brackets [] is optional.

Command         Arguments       Description

-q              <empty>         disables human style output

alien           <empty>         Discovers untracked files.
from [-regex]   path/file       Discovers what installed a file.

search          "phrase"        Searches for "phrase" in the long and short
                                spell descriptions and in the spell name.
search -name    "phrase"        Searches for "phrase" in the spell name.
search -short   "phrase"        Searches for "phrase" in the short spell
                                descriptions

provides        feature         Displays spells that provide the feature.

what            spell           Prints the spell's description.
short           spell           Prints the spell's short description.
where   -path   spell           Prints the spell's section or full path.
website | url   spell           Prints the spell's website.
install         spell [version] Views an install log, and sorcery log files for to the spell.
install-full    spell [version] Views an install log including all sorcery state files.
install-spell   spell [version] Views an install log without any sorcery files included.
installed      [spell]          Views installed spells.
version         spell           Views version of spell installed,
                                 and version in the grimoire.
versions        spell           Views version of spell in all grimoires
patchlevels     spell           Views PATCHLEVEL and SECURITY_PATCH value
                                 of spell in all grimoires
license         spell           Views the license of the given spell(s)
license         section         Views the licenses of spells in the given
                                 section(s)
license         license         Views information about the given license(s).
compile         spell [version] Views a compile log. If no optional version
                                 was given, try the installed version,
                                 if the spell is not installed use the
                                 version in the grimoire.
sources         spell           Lists the source files for a spell.
source_urls     spell           Lists the source urls for a spell.
history         spell           Shows history for a spell.

sum            [spell]          Prints checksums.
md5sum         [spell]          Prints md5sums.
size            spell           Prints total size of all files installed
                                 by this spell
size            -all            Prints total size of all spells, as well
                                 as size of the largest spell
export
                                Makes snapshot of box's configuration:
                                 This includes the list of installed spells,
                                 their dependencies and configure options.
import [--deprecated] snapshot
                                Restores snapshot. --deprecated activates
                                 the old behaviour, useful for old caches.

section        [section]        Lists all sections. Or all spells in
                                 the specified section.
maintainer     [section]        Lists who is the maintainer for a section
grimoire       [grimoire]       Views a text listing of all grimoires.
                                 Or of the specified grimoire.
grimoires                       Views list of installed grimoires' names
html    [-s]   [grimoire]       Views a html listing of all grimoires.
                                 Or of the specified grimoire.
                                 Additionally displays links to the source
                                 files when -s is given.

newer           20020521        Shows available spells newer than May 21, 2002.
older           20010521        Shows spells installed before May 21, 2001.
newer last_sorcery_update       Shows spells newer than your previous sorcery
                                 update
newer last_cast                 Shows spells newer than your last casting

voyeur         [delay or spell]
                                Peeks into spell compilation.

orphans        <empty>          Displays installed spells that no installed
                                 spells explicitly depend on.

depends [--fast] [--required] spell [level]
                                 Displays the spells that explicitly or
                                 recursively depend on this spell,
                                 up to \$level levels (infinity if omitted)
                                 --fast omits some information but runs faster
                                 --required omits runtime dependencies
                                 NOTE: the target spell must be installed and
                                 only enabled dependencies are shown

dependencies    [-c ] [--no-optionals ] spell [level]
                                 Displays the spells this spell explicitly
                                 or recursively depends on, up to \$level
                                 levels (infinity if omitted). -c turns
                                 on compact mode, which will prevent
                                 previously shown trees from being displayed
                                 (avoids loops). --no-optionals skips
                                 optional spells

SCRIPT NAME      spell            will print the spell script for that spell.

activity        <empty>          View the activity log

install-queue   <empty>          View the install queue

remove-queue    <empty>          View the remove queue

checkmd5s       [spell|section]  Print a md5 check of spells

system-info                      Show information about a Source Mage system

tablet           spell <option>  Show spell information from tablet.
                                 Options: info, depends, sub_depends, spell_config
                                 rsub_depends, roots, dirs, all

show-held                        Shows all held spells.

show-exiled                      Shows all exiled spells.

time [--last|--median|--mean|--weigh-last] spell(s)
                                Shows previous spell cast time (without summon)
                                and total time if more than one spell is
                                specified. Can also show median and mean times.
time --full     spell(s)
                                Shows previous spell cast time (without summon)
                                computed in (all) different manners (see above)

time-system [--no-orphans] [--last|--median|--mean|--weigh-last]
                                Shows system cast time (without summon)

EOF
}

#-----
## override column so that we can pass -q to not columnate.
#-----
function maybe_column()  {
  if [ -n "$GAZE_VERBOSE" ]; then
    cat
  else
    column "$@"
  fi
}

#-----
## THIS FUNCTION IS DEPRECATED
## To make the <@function export_snapshot> actualy be useful, an import
## is quite handy.
## @param snapshot file
#-----
function import_snapshot_old()  {
  message "${PROBLEM_COLOR}This behaviour is deprecated and can be removed at any time!$DEFAULT_COLOR"

          SNAPSHOT=$1
  SOURCE_DIRECTORY=$BUILD_DIRECTORY/snapshot

  if  [  -f  "$1"  ];  then

    cd  $BUILD_DIRECTORY
    mk_source_dir          $SOURCE_DIRECTORY

    if  [  -n  "$EXTENSION"  ];  then
      $COMPRESSBIN -dc $SNAPSHOT  |  tar  -x
    else
      tar  -xf  $SNAPSHOT
    fi

    cd  $SOURCE_DIRECTORY

    for  LINE  in  `cat  install`;  do
      push_install_queue  $LINE
    done
    report  $INSTALL_QUEUE  "Install Queue"

    cp  -ai  local  /etc/sorcery
    cp  -ai  etc    /

    cd  /
    rm_source_dir  $SOURCE_DIRECTORY

  else

    message  "Unable to find snapshot  \"$SNAPSHOT\""
    false

  fi

}

#-----
## Construct and echo a filename to save a snapshot in.
#-----
function mk_snapshot_filename() {
  echo "snapshot-$HOSTNAME-$(date -u +%Y%m%d).tar$EXTENSION"
}

#-----
## Write spell configurations and a list of installed spells to an archive.
## See <@function import_snapshot>
## @param snapshot file
#-----
function export_snapshot()  {
  local snapshot=$1

  if [[ $UID != 0 ]]; then
    error_message "${PROBLEM_COLOR}gaze export needs to be run as root, aborting...$DEFAULT_COLOR"
    exit 1
  fi

  SOURCE_DIRECTORY=$BUILD_DIRECTORY/snapshot
  mk_source_dir "$SOURCE_DIRECTORY" || return 1
  mkdir "$SOURCE_DIRECTORY/etc_sorcery_local"

  cp -a "$CONFIG_CACHE/depends/" "$CONFIG_CACHE/config_option_cache/" \
    "$SOURCE_DIRECTORY/etc_sorcery_local" || return 2

  get_all_spells_with_status ok > "$SOURCE_DIRECTORY/install"

  if [[ -n $EXTENSION ]]; then
    tar -C "$BUILD_DIRECTORY" -c snapshot | $COMPRESSBIN > "$snapshot"
  else
    tar -C "$BUILD_DIRECTORY" -cf "$snapshot" snapshot
  fi || return 3

  rm_source_dir "$SOURCE_DIRECTORY"
  message  "Snapshot \"$snapshot\" created."
}

#-----
## Reads a snapshot created by <@function export_snapshot>, restores
## spell configuration and saves the list of installed spells into the
## install queue.
## @param snapshot file
#-----
function import_snapshot()  {
  if [[ $UID != 0 ]]; then
    error_message "${PROBLEM_COLOR}gaze import needs to be run as root, aborting...$DEFAULT_COLOR"
    exit 1
  fi

  if [[ $1 == '--deprecated' ]] ; then
    import_snapshot_old "$2"
    return
  fi

  local snapshot=$1
  if ! [[ -r $snapshot ]]; then
    error_message "${PROBLEM_COLOR}Unable to read snapshot \"$snapshot\", aborting...$DEFAULT_COLOR"
    exit 1
  fi

  message -n "Saving previous configuration... "
  export_snapshot "$TMP_DIR/$(mk_snapshot_filename)" || return 13
  message "Done."

  SOURCE_DIRECTORY=$BUILD_DIRECTORY/snapshot
  mk_source_dir "$SOURCE_DIRECTORY" || return 2

  # FIXME: use uncompress_unpack
  if [[ -n $EXTENSION ]]; then
    $COMPRESSBIN -dc "$snapshot" | tar -C "$BUILD_DIRECTORY" -x
  else
    tar -C "$BUILD_DIRECTORY" -xf "$snapshot"
  fi || return 3

  local spell
  for spell in $(cat "$SOURCE_DIRECTORY/install"); do
    push_queue "$INSTALL_QUEUE" "$spell"
  done || return 4

  cp -a "$SOURCE_DIRECTORY/etc_sorcery_local"/* "$CONFIG_CACHE" || return 5

  rm_source_dir  "$SOURCE_DIRECTORY"
  message  "$snapshot imported, please use 'cast --queue' to start compiling."
}

#-----
## Run a simple checksum of a list of files in a file
## Is this used anywhere?
## @param File with list of files the sum
#-----
function checksum() {
  for FILE in `cat $1 | files`; do
    sum -s  $FILE
  done
}

#-----
## Run an md5sum of a list of files in a file
## Is this used anywhere?
## @param File with list of files the sum
#-----
function md5sum_files() {
  for FILE in `cat $1 | files`; do
    md5sum  "$FILE"
  done
}

#-----
## Find all files on the system not installed by a spell
## This can be quite time consuming.
#-----
function alien()  {

  if [[ $GAZE_VERBOSE != false ]] ; then
    message  "In a few minutes I will print files found on this disk"
    message  "that were not installed by sorcery.  This is not a"
    message  "security feature!  Files could still be lurking"
    message  "undetected on this box."
  fi

  rm    -f  $TMP_DIR/gaze.found
  rm    -f  $TMP_DIR/gaze.known

  [[ $GAZE_VERBOSE != false ]] &&
  message  "Discovering installed files..."
  { cat $SORCERY_INSTALL_LOG ; find $INSTALL_LOGS/ -type f|xargs cat ; }  |
    files  |  sort  >  $TMP_DIR/gaze.known

  [[ $GAZE_VERBOSE != false ]] &&
  message  "Discovering ambient files..."
  find $GAZE_ALIEN_PATHS 2>/dev/null | files | filter "$EXCLUDED" | sort >$TMP_DIR/gaze.found

  diff  -B  -a  -d  $TMP_DIR/gaze.found  $TMP_DIR/gaze.known  |
  grep  -v  "^> "                                     |
  grep      "^< "                                     |
  cut  -c  3-                                         |
  filter  "$PROTECTED"

  rm  -f  $TMP_DIR/gaze.found
  rm  -f  $TMP_DIR/gaze.known

}

#-----
## Lists sections and spells in a grimoire.
## Used by <code>gaze grimoire</code>
## @param Grimoire name
## @Stdout catalog
#-----
function gaze_catalog()  {

  local grimoire
  {
  if [[ $# -gt 0 ]]; then
        grimoire=$(codex_find_grimoire $1)
        if [[ $? != 0 ]]; then
            echo "No such grimoire $1"
            exit 1;
        fi
  fi

  [[ $GAZE_VERBOSE != false ]] && echo  "Sorcery Grimoire for `date  -u`"

  if [ $grimoire ]; then
        echo "Grimoire: " $(smgl_basename $grimoire)
  else
        echo "Grimoires: " $(codex_get_all_grimoires | get_basenames)
  fi

  COUNT=0

  for  SECTION  in  `codex_get_all_sections $grimoire`;  do
    if [[ $GAZE_VERBOSE != false ]]; then
      echo
      echo  "-------------------------------------------------"
      echo  "SECTION: $(  smgl_basename  $SECTION  )"
      echo  "-------------------------------------------------"
    else
      echo
      echo  "SECTION: $(  smgl_basename  $SECTION  )"
    fi
    for  spell  in  `codex_get_spells_in_section $SECTION`;  do
      smgl_basename $spell
      ((  COUNT++  ))
    done
  done

  echo
  echo  "Total spells:  $COUNT"
  } | $PAGER
}

#-----
## Lists all sections and spells, output is in HTML format
## @param Grimoire
## @Stdout HTML Catalog
#-----
function gaze_catalog_html()  {

  local grimoire COLS=4

  if [[ $1 == "-s" ]]; then
        shift;
        (( COLS++ ))
  fi

  if [[ $# -gt 0 ]]; then
        grimoire=$(codex_find_grimoire $1)
        if [[ $? != 0 ]]; then
            echo "No such grimoire $1"
            exit 1;
        fi
  fi

  echo  "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 STRICT//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"
  echo  "<html xmlns=\"http://www.w3.org/1999/xhtml\">"
  echo  "<head>"
  echo  "<title>Sorcery Grimoires for `date  -u`</title>"
  echo  "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />"
  echo  "<style type=\"text/css\" media=\"all\"> <!--"
  echo  "body"
  echo  "{"
  echo  "background: white;"
  echo  "color: black;"
  echo  "font-family: Verdana, Arial, Helvetica, sans-serif;"
  echo  "font-size: 10pt;"
  echo  "margin:0px;"
  echo "}"
  echo ""
  echo "h1"
  echo "{"
  echo "background: white;"
  echo "color: green;"
  echo "text-align: center;"
  echo "font-family: Verdana, Arial, Helvetica, sans-serif;"
  echo "font-size: 14pt; "
  echo "}"

  echo "h2"
  echo "{"
  echo "background: white;"
  echo "color: green;"
  echo "text-align: center;"
  echo "font-family: Verdana, Arial, Helvetica, sans-serif;"
  echo "font-size: 12pt; "
  echo "}"

  echo "table"
  echo "{"
  echo "width: 100%;"
  echo "border-style: solid;"
  echo "border-color: black;"
  echo "border-width: 2px;"
  echo "}"

  echo "th"
  echo "{"
  echo "vertical-align: top;"
  echo "text-align: left;"
  echo "background: white;"
  echo "color: black;"
  echo "border-style: solid;"
  echo "border-color: black;"
  echo "border-width: 2px;"
  echo "font-size:12pt;"
  echo "}"

  echo "td"
  echo "{"
  echo "background: white;"
  echo "color: black;"
  echo "vertical-align: top; "
  echo "text-align: left;"
  echo "border-style: solid;"
  echo "border-color: black;"
  echo "border-width: 2px;"
  echo "font-size: 10pt;"
  echo "}"

  echo "--></style>"

  echo  "</head>"
  echo  "<body>"

  echo  "<table>"

  echo "<tr>"
  echo "<th colspan=\"${COLS}\">"
  echo "<h1>Sorcery Grimoires</h1>"
  echo "<h1>$(date -u)</h1>"

  if [ $grimoire ]; then
        echo  "<h1>Grimoire: " $(smgl_basename $grimoire)"</h1>"
  else
        echo  "<h1>Grimoires: " $(codex_get_all_grimoires | get_basenames)"</h1>"
  fi

  echo  "</th>"
  echo  "</tr>"

  echo  "<tr>"
  echo  "<th>Spell</th>"
  echo  "<th>Version</th>"
  echo  "<th>Updated</th>"
  echo  "<th>Website</th>"
  [[ $COLS -eq 5 ]] && echo "<th>Source</th>"
  echo  "</tr>"

  ((  COUNT=0  ))

  for  SECTION  in  `codex_get_all_sections $grimoire`;  do
    echo  "<tr>"
    echo  "<th colspan=\"${COLS}\">"
    echo  "<h2>$( smgl_basename  $SECTION )</h2>"
    echo  "</th></tr>"
    for  SPELL  in  `codex_get_spells_in_section  $SECTION`;  do
      (
        codex_set_current_spell  $SPELL

        echo  "<tr>"
        if  [  "$SPELL"  ==  "linux"  ]   ||
            [  "$SPELL"  ==  "glibc"  ];  then
            BOLD="<th>"
          UNBOLD="</th>"
        else
            BOLD="<td>"
            UNBOLD="</td>"
        fi
        if  [  -z  "$UPDATED"  ]  &&  [  "$ENTERED"  ];  then
          UPDATED=$ENTERED
        fi
        echo  "${BOLD}${SPELL}${UNBOLD}"
        echo  "${BOLD}${VERSION}${UNBOLD}"
        echo  "<td>$UPDATED</td>"

        if  [  "$WEB_SITE"  !=  "unknown"  ];  then
            WEBSITE="`echo  $WEB_SITE  |  cut  -c-30`..."
            echo  "<td>"
            echo  "<a href=\"$WEB_SITE\">$WEBSITE</a>"
            echo  "</td>"
        else
            echo  "<td></td>"
        fi
        if [[ $COLS -eq 5 ]]; then
            echo "<td>"
            echo "<a href=\"$SOURCE_URL\">$(echo $SOURCE | cut -c-25)</a>"
           i=2
           ii=SOURCE${i}
           while  [  -n "${!ii}"  ];  do
               iii="${ii}_URL"
               echo "<br />"
               echo "<a href=\"${!iii}\">$(echo ${!ii} | cut -c-25)</a>"
               i=$(($i+1))
               ii=SOURCE${i}
           done
           echo "</td>"
        fi
        echo  "</tr>"
      )
      ((  COUNT++  ))
    done
  done


  echo  "<tr>"
  echo "<th colspan=\"${COLS}\">Total spells:  $COUNT</th>"
  echo "</tr>"
  echo  "</table></body></html>"
}

#-----
## Display a file. Decompresses it if necessary.
## @Note We may want to move this function as it is a generaly handy function
## @param File to display
## @param Message to display if file doesn't exist
#-----
function display()  {
  local file=$(FUZZ=on guess_filename "$1")
  show_file "$file" no "$2"
}

#-----
## List spells created more recently than the given date
## @param Date
#-----
function newer()  {

  local DATE=$1
  local COMPUTE

  if [ x"$DATE" == x"last_sorcery_update" ]; then
    COMPUTE='($3=="update") { a=a+1; if (a>1) { print $1 ; exit } }'
  elif [ x"$DATE" == x"last_cast" ]; then
    COMPUTE='($3 == "cast" && $6 == "success") { print $1 ; exit }'
  elif ! date -d "$DATE" +%Y%m%d > /dev/null; then
    help | $PAGER
    exit 1
  fi

  if [ -n "$COMPUTE" ]; then
    DATE=$( tac $ACTIVITY_LOG | awk -F '\t| |:' "$COMPUTE" )
    if [ -z "$DATE" ]; then
      message "${PROBLEM_COLOR}No previous $1 date found${DEFAULT_COLOR}"
      exit 1
    fi
  fi

  if  [  -n  "$DATE"  ];  then
  (
    echo "Grimoire|Section|Spell|Grimoire Version|Installed Version|Added"
    echo "--------|-------|-----|----------------|-----------------|-----"
    for  SPELL_DIR  in  `codex_get_all_spells`;  do
      unset ENTERED
      .  "$SPELL_DIR/DETAILS" 1>/dev/null 2>&1
      if  [  "$ENTERED"  ]  &&  [  $ENTERED  -gt  $DATE  ];  then
        codex_set_current_spell  $SPELL_DIR
        echo "$GRIMOIRE_NAME|$SECTION|$SPELL|$VERSION|${INSTALLED:="-"}|$ENTERED"
      fi
    done
  ) | maybe_column -t -s "|"
  else
    help  |  $PAGER
  fi

}

#-----
## List spells created less recently than the given date
## @param Date
#-----
function older()  {

  DATE=$1
  if  [  -n  "$DATE"  ];  then
  (
    echo "Grimoire|Section|Spell|Grimoire Version|Installed Version|Added"
    echo "--------|-------|-----|----------------|-----------------|-----"
    for  SPELL_DIR  in  `codex_get_all_spells`;  do
      unset ENTERED
      .  "$SPELL_DIR/DETAILS" 1>/dev/null 2>&1
      if  [  "$ENTERED"  ]  &&  [  $ENTERED  -lt  $DATE  ];  then
        codex_set_current_spell  $SPELL_DIR
        echo "$GRIMOIRE_NAME|$SECTION|$SPELL|$VERSION|${INSTALLED:="-"}|$ENTERED"
      fi
    done
  ) | maybe_column -t -s "|"
  else
    help  |  $PAGER
  fi

}

#-----
## Find all install logs that mention the given string,
## discarding hits that match state files
## @param mode (-regex to not match literally)
## @param Search string
## @Stdout grep results
#-----
function show_from()  {
  local mode string

  if [[ -z $2 ]]; then
    string=$1
  else
    mode=$1
    string=$2
  fi

  if [[ -z $string ]]; then
    error_message "${PROBLEM_COLOR}Missing search string parameter!$DEFAULT_COLOR"
    exit 1
  fi

  cd $INSTALL_LOGS

  local matches=$(
    find . -type f -printf "%f\n" |
    # we use grep -e to protect against patterns starting with a dash
    if [[ $mode == -regex ]]; then
      xargs grep -e "$string"
    else
      # match the string literally, but only those at the end of the line
      # substr indices start with 1
      xargs awk -v str="$string" '{ if (substr($0, length($0)-length(str)+1) == str) printf ("%s: %s\n", FILENAME, $0) }'
    fi |
    seperate_state_files /dev/stdin /dev/stdout /dev/null | sort
  )

  if [[ -n $matches ]]; then
    if [[ $GAZE_VERBOSE != false ]]; then
      echo "$matches"
    fi
    return 1
  fi
  return 0
}

#-----
## Generalized show component of a spell, BUILD, DEPENDS, etc...
## @param Component
## @param Spell
#-----
function show_spell_component()  {

  local        COMPONENT=$1
  local       SPELL_NAME=$2
  local  SPELL_DIRECTORY=`codex_find_spell_by_name  $SPELL_NAME`

  if  [  -z  "$SPELL_DIRECTORY"  ]; then
    message "No such spell '$SPELL_NAME'"
    exit 1
  fi

  if  [  -e  $SPELL_DIRECTORY/$COMPONENT  ];  then
    $PAGER $SPELL_DIRECTORY/$COMPONENT
  fi

}


#-----------------------------------------------------------------------
## parameter processing for the search routines.
## the case statement should be self-explanatory
## @param (optional) Type pf search (-name or -short)
## @param words to search for
#-----------------------------------------------------------------------
function gaze_search() {
    case $1 in

     -name) shift; real_name_search  "$@"  ;;
    -short) shift; real_short_search "$@"  ;;
         *)        real_long_search  "$@"  ;;

    esac | awkuniq
}

#-----------------------------------------------------------------------
##
## searches for pattern(s) in the name of all spells.
## it searches in the codex.index files for the sake of speed
##
## @Args Patterns
##
#-----------------------------------------------------------------------
function real_name_search() {
    local grimoire pattern

    for grimoire in $(codex_get_all_grimoires); do
        for pattern in "$@"; do
            gawk ' BEGIN {
                        OFS=""
                        IGNORECASE=1
                        quiet = "'$GAZE_VERBOSE'"
                    }
                    /^[^[:blank:]]*'"$pattern"'/ {
                        if (quiet) {
                            print $1
                        }
                        else {
                            print "'"$pattern"' -> ", $1
                        }
                    }
                ' "$grimoire/$SPELL_INDEX_FILE" 2>/dev/null
        done
    done
}


#-----------------------------------------------------------------------
##
## Searches for something in a specified grimoire. Not really sure what
## it looks for or why.
##
## @param Path to grimoire
## @param Spell to look for
## @param Patern to find in the files
## @Stdout The full path to the file, /var/lib/sorcery/codex/grimoire/games/coal/DETAILS
##
#-----------------------------------------------------------------------
function grep_find_grimoire() {
        local path=$1
        local name=$2
        local pattern="$3"

        codex_find_in_grimoire "$path" "$name" | xargs grep -ilE -- "${pattern}"
}

#-----------------------------------------------------------------------
##
## searches for pattern(s) in the SHORT field of every SPELL in every
## grimoire
##
## @Args Patterns
##
#-----------------------------------------------------------------------
function real_short_search() {
    local pattern grimoire spell spellname spelldir

    for pattern in "$@"; do
        for grimoire in $(codex_get_all_grimoires); do
            for spell in $(
    grep_find_grimoire $grimoire "DETAILS" "SHORT=.*${pattern}"
                        ); do
                smgl_dirname "$spell" spelldir
                smgl_basename "$spelldir" spellname
                if [[ $GAZE_VERBOSE == false ]]; then
                    echo $spellname
                else
                    echo "$pattern -> $spellname"
                fi

            done
        done
    done
}



#-----------------------------------------------------------------------
##
## searches for pattern(s) in the long description of every SPELL in every
## grimoire
##
## @Args Patterns
##
#-----------------------------------------------------------------------
function real_long_search()  {
  local atSpell=0
  local file pattern
  local SEARCH SEARCH_RESULTS
  local spelldir spellname

  if ! [[ $GAZE_VERBOSE == false ]] ; then
    echo  "Searching...   "
  fi

  let i=0

  for pattern in "$@"; do
    SEARCH[$i]=-e
    let i++
    SEARCH[$i]=$pattern
    let i++
  done

  for file in `codex_get_all_spells | sed 's/$/\/DETAILS/' | xargs grep -ilE "${SEARCH[@]}"`; do
    for ((i=1;i<${#SEARCH[@]};i+=2)) ; do
      pattern=${SEARCH[$i]}
      SEARCH_RESULTS=$(gawk 'BEGIN{ORS = ""; IGNORECASE=1; inLongDesc=0}
        /'"${pattern}"'/{
          if(/^[[:blank:]]*SPELL=.*'"${pattern}"'/)   {print "(Name Match)";        exit 0;}
          if(/^[[:blank:]]*SHORT=.*'"${pattern}"'/)   {print "(Short Description)"; exit 0;}
          if(inLongDesc) {print "(Description)";       exit 0;}
        }
        /cat[[:blank:]]*<<[[:blank:]]*EOF/{inLongDesc = 1;}
        /^EOF$/{inLongDesc=0;} ' $file)

      if [[ ${SEARCH_RESULTS} ]]; then
        smgl_dirname "$file" spelldir
        smgl_basename "$spelldir" spellname
        if [[ $GAZE_VERBOSE == false ]]; then
          echo "$spellname"
        else
          clear_line
          echo "$pattern ->  $spellname ${SEARCH_RESULTS}"
        fi
      fi
    done
  done

  if ! [ "$GAZE_VERBOSE" == "false" ]; then
    clear_line
  fi


}

#---------------------------------------------------------------------
##
## Given a feature, shows a list of spells that provide the feature
## or functionality.  For example:
##
##    % gaze provides alsa-drivers
##    alsa-driver
##    linux-devel
##    linux-dj
##
## This output indicates that alsa-driver, linux-devel, and linux-dj
## all provide the alsa-drivers feature.
##
## @param feature
##
#---------------------------------------------------------------------
gaze_provides()  {

local spell

  for feature in "$@"; do
        ! [[ $GAZE_VERBOSE == false ]] &&
        message "${SPELL_COLOR}${feature}:${DEFAULT_COLOR}"
        spell=$(find_providers "$feature")
        if [[ "$spell" ]]; then
                echo "$spell"
        else
                echo "no providers found"
        fi
  done
}

#-----
## Watches a specific exhibisionist
## @param PID of exhibitionist
#-----
function specific_voyeur()
{
  if ! [ -d "/tmp/liblock-0/cast.$1" ]
  then
    return 1
  fi
  nice -n +20                   \
   tail $(find /tmp/sorcery/cast/ -name $1.compile.log )     \
    --follow=name --pid=$(ls "/tmp/liblock-0/cast.$1") 2>/dev/null
}

#-----
## Watches the first exhibisionist found
## @param PID of exhibitionist
#-----
function any_voyeur()
{
  # We happily assume no spell names contain "cast."
  local FILE=`find /tmp/liblock-0 -maxdepth 1 -mindepth 1 -name "cast.*" |
         sed "s/.*\/cast\.//" | head -n 1`
  [ $FILE ] || return 1
  debug "voyeur" "Looking at spell \"$FILE\""
  nice -n +20                                               \
    tail $(find /tmp/sorcery/cast/ -name $FILE.compile.log )\
         --follow=name --pid=$(ls "/tmp/liblock-0/cast.$FILE") 2>/dev/null
}

#-----
## Start waiting for an exhibisionist.
## @param (optional) Not sure if this is used... specifies a section or something
#-----
function gaze_activate_voyeur()  {

  if  [  -n  "$1"  ]  &&
      !  find_section  $1  >  /dev/null
  then  ((  DEFAULT_DELAY  =  $1  *  60  ))
        shift  1
  fi

  for  SPELL  in  $@;  do
    specific_voyeur $SPELL
  done

  DEFAULT_DELAY=${DEFAULT_DELAY:=60}
  DELAY=$DEFAULT_DELAY
  message  "${MESSAGE_COLOR}Waiting ${DEFAULT_DELAY} seconds for a cast to begin.${DEFAULT_COLOR}"
  while ((DELAY>0));
  do
    if any_voyeur
    then
      DELAY=$DEFAULT_DELAY
      message "${MESSAGE_COLOR}Waiting ${DEFAULT_DELAY} seconds for another cast to begin.${DEFAULT_COLOR}"
      global_clean_resources # normally an internal liblock function, inserted to clean out dead casts
    else
      sleep 1
      let DELAY--
    fi
  done

}

#-----
## Show spells that have no other spell depending on them
#-----
function show_orphans()  {
  local spell each
  compute_reverse_installed_depends my_hash
  for each in $(get_all_spells_with_status ok); do
    hash_get_ref my_hash $each spell
    if [[ ! $spell ]]; then
      echo "$each"
    fi
  done
}

#-----
## Show spells that have other spell depending on them
#-----
function show_non_orphans()  {
  local spell each
  compute_reverse_installed_depends my_hash
  for each in $(get_all_spells_with_status ok); do
    hash_get_ref my_hash $each spell
    if [[ $spell ]]; then
      echo "$each"
    fi
  done
}



#---------------------------------------------------------------------
##
## Shows the website/home page for the given spell.
## @param Spell
##
#---------------------------------------------------------------------
function gaze_show_website()  {

  for spell in $@; do
    if  codex_set_current_spell_by_name  $spell;  then
      if  [  -n  "$WEB_SITE"  ];  then
        ! [[ $GAZE_VERBOSE == false ]] &&
        message "${SPELL_COLOR}${spell}:${DEFAULT_COLOR}"
        echo  $WEB_SITE
      else
        echo  "  "
        echo  "No website found for '$spell'.  If you know of a website for"
        echo  "'$spell',  please let the Source Mage developers know so that"
        echo  "it can be included in future versions of the Source Mage"
        echo  "grimoire.  You can report the omission at the Source Mage"
        echo  "bug tracking website:"
        echo  "  "
        echo  "           http://bugs.sourcemage.org/"
      fi
    else
      echo  "  "
      echo  "'$spell' is not a spell in the current grimoire(s).  If it's"
      echo  "not a typo and it's a spell you'd really like to see, consider"
      echo  "creating a spell for it yourself.  For instructions on how to"
      echo  "write & submit spells, see the Source Mage Wiki:"
      echo  "  "
      echo  "             http://wiki.sourcemage.org."
    fi
  done
}

#---------------------------------------------------------------------
##
## Shows the maintainer for the given section.
## @param section
##
#---------------------------------------------------------------------
function show_maintainer()  {

  local section="$1"

  {
    echo  "Grimoire|Section|Maintainer"
    echo  "--------|-------|----------"

    for GRIMOIRE in $(codex_get_all_grimoires); do
      codex_set_grimoires $GRIMOIRE
      SECTION=`codex_find_section_by_name $section`
      if [[ -d "$SECTION" ]]; then
        if [[ -f "$SECTION/MAINTAINER" ]]; then
          echo "$(smgl_basename ${GRIMOIRE})|$section|$(<$SECTION/MAINTAINER)"
        else
          echo "$(smgl_basename ${GRIMOIRE})|$section|-"
        fi
      else
          echo "$(smgl_basename  ${GRIMOIRE})|-|-"
      fi
      codex_set_grimoires $GRIMOIRES
    done
  } | maybe_column -t -s "|"

}


#---------------------------------------------------------------------
##
## Given a section name, shows a table of spells in that section along
## with their grimoire version and installed verion
## @param Section
## @param ...
##
#---------------------------------------------------------------------
function gaze_show_section()  {

  local SECTION_NAME

  if  [  $# -gt 0  ]; then

    (
      for  SECTION_NAME  in  $@;  do
        local SECTION=$(codex_find_section_by_name  $SECTION_NAME)
        [[ $SECTION ]] && codex_get_spell_names $SECTION
      done
    ) | maybe_column

  else

    codex_get_all_section_names | maybe_column

  fi

}


#---------------------------------------------------------------------
##
## Given a section name, shows a table of spells in that section along
## with their grimoire version and installed verion
## @param Section
##
#---------------------------------------------------------------------
function gaze_show_section_version_table()  {

   local  SPELLS=`codex_get_spells_in_section $1`

   (

     echo  "Grimoire|Section|Spell|Grimoire Version|Installed Version"
     echo  "--------|-------|-----|----------------|-----------------"

     for  spell  in  $SPELLS;  do

       codex_set_current_spell  $spell                            &&
       local  INSTALLED=`installed_version  $SPELL`               &&
       echo  "$GRIMOIRE_NAME|$SECTION|$SPELL|${VERSION:="-"}|${INSTALLED:="-"}"

     done

   ) | maybe_column -t -s "|"

}


#---------------------------------------------------------------------
##
## Shows the versions of spells, both the version in the grimoire and
## the version installed on the system.
## @param Spell
## @param ...
##
#---------------------------------------------------------------------
function gaze_show_spell_version_table()  {

  (
    echo  "Grimoire|Section|Spell|Grimoire Version|Installed Version"
    echo  "--------|-------|-----|----------------|-----------------"

   for  SPELL  in  $@; do

      codex_set_current_spell  $SPELL                        &&
      local  INSTALLED=`installed_version  $SPELL`           &&
      echo  "$GRIMOIRE_NAME|$SECTION|$SPELL|${VERSION:="-"}|${INSTALLED:="-"}"

    done

  ) | maybe_column -t -s "|"

}


#---------------------------------------------------------------------
##
## Shows the versions of spells, both the version in the grimoire and
## the version installed on the system.
## @param Spell or section
## @param ...
##
#---------------------------------------------------------------------
function gaze_show_version()  {

  local SPELLS_AND_SECTIONS=$@
  local SPELLS=
  local UNKNOWN=

  for  spell_or_section  in  $SPELLS_AND_SECTIONS;  do

    if  codex_find_spell_or_section_by_name  $spell_or_section;  then

      [  -n  "$CODEX_FOUND_SECTION"  ]                                      &&
      gaze_show_section_version_table  $CODEX_FOUND_SECTION  2>  /dev/null  &&
      echo " "

      [  -n  "$CODEX_FOUND_SPELL"  ]    &&
      SPELLS="$SPELLS $CODEX_FOUND_SPELL"

    else
      UNKNOWN="$spell_or_section $UNKNOWN"
    fi

  done

  [  -n  "$SPELLS"  ]  &&
  gaze_show_spell_version_table  $SPELLS  2>  /dev/null  &&
  echo " "


  if [[ -n $UNKNOWN ]]; then
    message "Unknown Spells or Sections"
    message "--------------------------"
    message "$UNKNOWN"
    return 1
  else
    return 0
  fi

}

#---------------------------------------------------------------------
##
## Shows the all versions of spell, all versions in all grimoires and
## the version installed on the system.
## @param Spell
##
#---------------------------------------------------------------------
function gaze_show_versions()  {

  local SPELL=$1

  if ! codex_does_spell_exist $SPELL
  then return 1
  fi

  (

  echo "Grimoire|Section|Spell|Grimoire Version|Installed Version"
  echo "--------|-------|-----|----------------|-----------------"

  #saving them, since they will be overwritten later
  if tablet_find_spell_dir "$SPELL" tablet; then
    # TODO: change this if it will be stored in the less volatile state/packages file
    tablet_get_grimoire_name $tablet installed_grimoire
  fi
  installed=$(installed_version $SPELL)

  for grimoire in $(codex_get_all_grimoires)
  do
    if SPELL_DIRECTORY=$(codex_cache_spell_lookup $SPELL $grimoire)
    then
      codex_set_current_spell $SPELL_DIRECTORY

      # old states don't have the name stored so fall back to similar old
      # broken behaviour where the first matching grimoire was used
      [[ -z $installed_grimoire ]] && installed_grimoire=$GRIMOIRE_NAME

      if [[ $GRIMOIRE_NAME == $installed_grimoire ]]
      then
        echo "$GRIMOIRE_NAME|$SECTION|$SPELL|$VERSION|${installed:="-"}"
      else
        echo  "$GRIMOIRE_NAME|$SECTION|$SPELL|$VERSION|-"
      fi

    else
      # handle also (re)moved spells
      smgl_basename "$grimoire" name
      if [[ $name == $installed_grimoire ]]; then
        echo "$name|-|-|-|$installed"
      else
        echo "$name|-|-|-|-"
      fi
    fi
  done

  ) | maybe_column -t -s "|"

  echo
}

#---------------------------------------------------------------------
##
## Shows the all versions of spell, all versions in all grimoires and
## the version installed on the system.
## @param Spell
##
#---------------------------------------------------------------------
function gaze_show_patchlevels()  {

  local SPELL=$1

  if ! codex_does_spell_exist $SPELL
  then return 1
  fi

  local TB_DIR

  local I_PATCH="-"
  local I_SPATCH="-"
  if tablet_find_spell_dir "$SPELL" TB_DIR; then
    tablet_get_patchlevel "$TB_DIR" I_PATCH
    tablet_get_security_patch "$TB_DIR" I_SPATCH
  fi


  local ECHO_INSTALLED=1
  (

  echo "Grimoire|Spell|Grimoire  |Grimoire  |Installed |Installed"
  echo "        |     |Regular   |Security  |Regular   |Security"
  echo "        |     |Patchlevel|Patchlevel|Patchlevel|Patchlevel"
  echo "--------|-----|----------|----------|----------|----------"

  for GRIMOIRE in $(codex_get_all_grimoires)
  do
    if SPELL_DIRECTORY=$(codex_cache_spell_lookup $SPELL $GRIMOIRE)
    then
      codex_set_current_spell $SPELL_DIRECTORY

      if [ $ECHO_INSTALLED -eq 1 ]; then
        echo "$GRIMOIRE_NAME|$SPELL|${PATCHLEVEL:-"0"}|${SECURITY_PATCH:-"0"}|${I_PATCH:-0}|${I_SPATCH:-0}"
        ECHO_INSTALLED=0
      else
        echo  "$GRIMOIRE_NAME|$SPELL|${PATCHLEVEL:-0}|${SECURITY_PATCH:-0}|-|-"
      fi

    else
      echo "$(smgl_basename $GRIMOIRE)|-|-|-|-|-"
    fi
  done

  ) | maybe_column -t -s "|"

  echo
}


#---------------------------------------------------------------------
##
## Given a section name, shows a table of spells in that section along
## with their licenses.
## @param Section
##
#---------------------------------------------------------------------
function gaze_show_section_license_table()  {

   local  SPELLS=`codex_get_spells_in_section $1`

   (

     echo  "Section|Spell|License(s)"
     echo  "-------|-----|----------"

     for  spell  in  $SPELLS;  do

       codex_set_current_spell  $spell        &&
       echo  "$SECTION|$SPELL|${LICENSE[@]}"

     done

   ) | maybe_column -t -s "|"

}


#---------------------------------------------------------------------
##
## Shows the licenses of spells
## @param Spell
## @param ...
##
#---------------------------------------------------------------------
function gaze_show_spell_license_table()  {

  (
    echo  "Spell|License(s)"
    echo  "-----|----------"

    for  SPELL  in  $@; do

      codex_set_current_spell  $SPELL                        &&
      echo "$SPELL|${LICENSE[@]}"

    done

  ) | maybe_column -t -s "|"

}


#---------------------------------------------------------------------
##
## Shows the information about the given licenses.
## @param Licence
## @param ...
##
#---------------------------------------------------------------------
function gaze_show_license_table()  {
  (
    echo  "Abbr|License Full Name|URL"
    echo  "----|-----------------|---"

    for  LICENSE  in  $@; do

      grep -i "^$LICENSE|"  ${SM_LICENSE_LIST}  2> /dev/null

    done

  ) | maybe_column -t -s "|"

}


#---------------------------------------------------------------------
##
## Shows lising of installed grmoires by grimoire name only.
##
#---------------------------------------------------------------------
function gaze_show_grimoires()  {

  ! [[ $GAZE_VERBOSE == false ]] &&  echo -n "Installed Grimoires: "
  echo $(codex_get_all_grimoires | get_basenames)
  exit

}


#---------------------------------------------------------------------
##
## Shows the licenses of spells if a spell or section name is given.
## Shows info a license if a license name is given.
## @param Spell, section, or license
## @param ...
##
#---------------------------------------------------------------------
function gaze_show_license()  {

  local SPELLS_AND_SECTIONS_AND_LICENSES=$@
  local SPELLS=
  local LICENSES=
  local UNKNOWN=

  for  spell_section_or_license  in  $SPELLS_AND_SECTIONS_AND_LICENSES;  do

    if  codex_find_spell_or_section_by_name  $spell_section_or_license;  then

      [  -n  "$CODEX_FOUND_SECTION"  ]                                      &&
      gaze_show_section_license_table  $CODEX_FOUND_SECTION  2>  /dev/null  &&
      echo " "

      [  -n  "$CODEX_FOUND_SPELL"  ]    &&
      SPELLS="$SPELLS $CODEX_FOUND_SPELL"

    elif  grep -iq "^`esc_str $spell_section_or_license`|"  ${SM_LICENSE_LIST} 2> /dev/null;  then
      LICENSES="$LICENSES $spell_section_or_license"
    else
      UNKNOWN="$spell_section_or_license $UNKNOWN"
    fi

  done

  [  -n  "$SPELLS"  ]                                    &&
  gaze_show_spell_license_table  $SPELLS  2>  /dev/null  &&
  echo " "

  [  -n  "$LICENSES"  ]                              &&
  gaze_show_license_table  $LICENSES  2>  /dev/null  &&
  echo " "


  [  -n  "$UNKNOWN"  ]                              &&
  message "Unknown Spells or Sections or Licenses"  &&
  message "--------------------------------------"  &&
  message "$UNKNOWN"

}

#-----
##
## Displays the installed version of spells
## @param Spell
## @param ...
##
#-----
function gaze_show_installed() {

  local total_rc=0
  if [ -z  "$1" ]
  then
    grep -v ':exiled:[^:]*$' $SPELL_STATUS | $PAGER
  else
    for spell in "$@"; do
      ! [[ $GAZE_VERBOSE == false ]] &&
      message  "${SPELL_COLOR}${spell}:${DEFAULT_COLOR}"
      VERSION=$(installed_version  $spell)
      if  [  -n  "$VERSION"  ]; then
        echo "$VERSION"
      else
        total_rc=1
        message  "not installed"
      fi
    done
  fi
  return $total_rc
}

#-----
##
## Display the SHORT description of spells
## @param Spell
## @param ...
##
#-----
function gaze_show_short_description() {

  for spell in $@; do
    if codex_find_spell_by_name $spell > /dev/null; then
        ! [[ $GAZE_VERBOSE == false ]] &&
        message "${SPELL_COLOR}${spell}:${DEFAULT_COLOR}"
        (
          codex_set_current_spell_by_name  $spell           &&
          echo "$SHORT"
        )                                                 ||
        { message  "No details found! Please file a bug!"
          return 1
        }
    else
      message "$spell -> no such spell"
    fi
    if ! [[ $GAZE_VERBOSE == false ]]; then echo; fi
  done
}

#-----
##
## Display the long description of spells
## @param Spell
## @param ...
##
#-----
function gaze_show_long_description() {

  for spell in $@; do
    if codex_find_spell_by_name $spell > /dev/null; then
        ! [[ $GAZE_VERBOSE == false ]] &&
        message "${SPELL_COLOR}${spell}:${DEFAULT_COLOR}"
        (
          codex_set_current_spell_by_name  $spell           &&
          codex_get_spell_description  $SPELL_DIRECTORY
        )                                       ||
        {
          message "No details found! Please file a bug!" &&
          return 1
        }
    else
      message "$spell -> no such spell"
    fi
    if [[ $GAZE_VERBOSE == false ]]; then
      echo --- --- ---
    else
      echo
    fi
  done
}

#-----
##
## Display the section spells are located in
## @param Spell
## @param ...
##
#-----
function gaze_show_where() {

  local SHOW_PATH
  if [[ $1 == "-path" ]]; then
    SHOW_PATH=true
    shift
  fi

  for spell in $@; do
    if [[ $SHOW_PATH == true ]]; then
      SECTION="$(codex_find_spell_by_name $spell)"
    else
      SECTION="$(codex_get_spell_section_name $spell)"
    fi

    if ! [[ $GAZE_VERBOSE == false ]]; then
      if [[ $SECTION ]]; then
        message "$spell -> $SECTION"
      else
        message "$spell -> no such spell"
      fi
    else
      [[ $SECTION ]] && message "$SECTION"
    fi
  done
}

#-----
##
## Display what spells depend on the given spell
## @param The given spell
##
#-----
function gaze_show_depends() {
    local fast all=yes
    while true; do
        if [[ $1 == --fast ]] ; then
            fast=yes
            shift
            continue
        elif [[ $1 == --required ]]; then
          unset all
          shift
          continue
        fi
        break
    done
    local spell=$1
    codex_does_spell_exist "$spell"  &&
    if [[ "$GAZE_VERBOSE" == false ]] || [[ "$fast" ]]; then
      show_up_depends "$1" "$2" "$fast" "$all"
    else
      show_up_depends  "$1" "$2" "verbose" "$all"|
      awk -F: '{ printf("%s depends on %s (%s)\n",$1,$2,$4);}'
    fi


}

#-----
##
## @See <@function gaze_show_depends>
## @param Spell
## @param (optional) depth to recurse for
##
#-----
function gaze_show_dependencies() {
    local FOUND SPELL NO_OPTIONALS

    while true; do
        # Check for the compact mode flag
        if [[ $1 == -c ]] ; then
            FOUND="$TMP_DIR/gaze.seen.$$"
            echo -n > $FOUND
            shift
            continue
        fi
        # Check for the no optionals flag
        if [[ $1 == --no-optionals ]] ; then
            NO_OPTIONALS=yes
            shift
            continue
        fi
        break
    done

    SPELL=$1
    codex_does_spell_exist "$SPELL"  || exit 1

    [[ $# == 2 ]] && MAX_DEPTH=$2

    (
        query() {
            return 0
        }
        depends() {
                [[ $1 == -sub ]] && shift 2
                recurse "$1" $DEPTH "depends"
                return 0
        }
        optional_depends() {
                [[ $1 == -sub ]] && shift 2
                [[ $NO_OPTIONALS ]] ||
                recurse "$1" $DEPTH "optional"
                return 0
        }
        runtime_depends() {
                [[ $1 == -sub ]] && shift 2
                recurse "$1" $DEPTH "runtime"
                return 0
        }
        suggest_depends() {
                [[ $1 == -sub ]] && shift 2
                recurse "$1" $DEPTH "suggest"
                return 0
        }
        force_depends() {
            return 0
        }
        sub_depends() {
            return 0
        }
        repeat () {
            local CHAR="$1" COUNT="$2"

            while (( COUNT-- )); do echo -en "$CHAR"; done
        }

# These functions shouldn't do anything in this function.
# Eventualy, they should be separated into two lists, ones
# that may be used in DEPENDS, and ones that shouldn't be
        define_functions ': ;'              \
        real_persistent_save real_query_string config_get_option \
        config_set_option real_config_query real_config_query_option \
        real_config_query_string real_list_add

# real_config_query_list should set $1 to something reasonable:
        real_config_query_list() { eval "$1='$3'"; }

        recurse () {
            local name=$1 DEPTH=$2 WHAT=$3
            local found_before=""

            if ! [[ $name ]] ; then
                return ;
            fi


            [[ $MAX_DEPTH ]] && [[ $DEPTH -ge $MAX_DEPTH ]] && return 1
            grep () {
               local foo
               smgl_which grep foo &&
               $foo "$@"
            }
            [[ $FOUND ]] &&
                grep -q '^'$name'$' $FOUND &&
                found_before=" (see above for tree)"

            repeat "\t" $DEPTH
            echo "$name ($WHAT)${found_before}"
            if [[ $found_before ]] ; then
                return ;
            elif [[ $FOUND ]] ; then
                echo "$name" >> $FOUND
            fi

            local SPELL_DIRECTORY=$(codex_find_spell_by_name $name)
            [[ -e "$SPELL_DIRECTORY/DEPENDS" ]] &&
            (
                let DEPTH++
                define_functions ':;' grep
                codex_get_spell_paths $SPELL_DIRECTORY
                source "$SPELL_DIRECTORY/DEPENDS" 2>/dev/null
            )
        }
        recurse $SPELL
    )
    [[ $FOUND ]] && rm $FOUND
}

#-----
##
## Display the size all installed spell use and the largest among them
##
#-----
function gaze_show_size_all () {
  local each date status version install_log
  local current_spell=0 current_size=0 current_info
  local max_size=0 max_spell total_size=0 total_files=0
  local installed_spells=$(all_spell_status | sed -n '/:exiled:/! s,:, ,gp')
  local spell_count=$(wc -l <<< "$installed_spells")

  echo "This will take a while and cause lots of disk I/O..."
  while read each date status version; do
    let current_spell++
    install_log="$INSTALL_LOGS/$each-$version"
    current_info=$(
      while read entry; do
        test -f "$entry" && echo "'$entry'"
      done < $install_log | xargs du -b -c | awk 'END {print $1,NR-1}'
    )
    current_info=( $current_info )
    current_size=${current_info[0]}
    if [[ $current_size -gt $max_size ]]; then
      max_size=$current_size
      max_spell=$each
    fi
    let total_size+=$current_size
    let total_files+=${current_info[1]}
    progress_bar $current_spell $spell_count
  done <<< "$installed_spells"
  clear_line
  echo $spell_count $total_size $total_files | awk \
    'END { print $1" spells -> "$2" bytes ("int($2/1024+0.5)" K, "int($2/1024/1024+0.5)" M, "int($2/1024/1024/1024+0.5)" G) in "$3" files." }'
  echo
  echo "Largest spell:"
  gaze_show_size $max_spell
}

#-----
##
## Display the space an installed spell uses
## @param Spell
## @param ...
##
#-----
function gaze_show_size () {
    local spell each

    if [[ $1 == "-all" ]]; then
        if [[ $# == 1 ]]; then
            gaze_show_size_all
        else
            help
        fi
        exit 0
    fi

    for spell in "$@"; do
        if ! spell_ok $spell ; then
          message "$spell is not installed"
          continue
        fi
        local version=$(installed_version $spell)
        local file="$INSTALL_LOGS/$spell-$version"
        if ! test -e $file ; then
           message "No install log for $spell ($file)"
           continue
        fi
        while read each; do
          test -f "$each" && echo $each
        done < $file | xargs du -b |
            awk '{ x += $1 }
                END { print "'$spell' -> " x " bytes ("int(x/1024+0.5)" K, "int(x/1024/1024+0.5)" M) in " NR " files." }'
    done
}

#---------------------------------------------------------------------
##
## displays a spell's install log
##
## @param spell - the spell name
## @param version - version for that spell
## @param type - If empty show the log without state files, if "spell"
##        show log without sorcery log files eitther, if "full" show the entire
##        log including sorcery state files
##
#---------------------------------------------------------------------
function gaze_install() {
  local SPELL=$1
  local VERSION=$2
  local TYPE=$3

  local log=$INSTALL_LOGS/$SPELL-$VERSION
  test -f $log || {
    message "Install log for $SPELL does not exist"
    return 1
  }

  if [[ "$TYPE" == full ]] ; then
    sort $log | $PAGER
  elif [[ "$TYPE" == spell ]] ; then
    seperate_state_files $log /dev/stdout /dev/null | sort | $PAGER
  else
    {
      seperate_state_files $log /dev/stderr /dev/stdout | grep $LOG_DIRECTORY
    } 2>&1 | sort | $PAGER
  fi

}

#---------------------------------------------------------------------
##
## used by system_info()
##
#---------------------------------------------------------------------
function figure_installed()
{
  local version
  version=$(installed_version  $1)
  if  [  -n  "$version"  ]; then
    message  "[${version}]"
  else
    message  "[not installed]"
  fi
}

#---------------------------------------------------------------------
##
## display spell information from tablet
## @param spell
## @param command (info, depends, sub_depends, spell_config, rsub_depends, roots, dirs, all)
## @Stdout information of spell from tablet
#---------------------------------------------------------------------
function gaze_tablet() {
  local spell=$1
  local command=$2
  local spell spell_directory spell_depends section_name version
  local patchlevel security_patch spell_persistent_config sub_depends build_api
  local file
  [[ -z $spell ]] && return 1
  if ! spell_ok $spell ;then
    message "${SPELL_COLOR}$spell${PROBLEM_COLOR} isn't installed!" \
            "${DEFAULT_COLOR}"
    return 1
  fi
  # get spell_directory that is used in all comands
  tablet_find_spell_dir $spell spell_directory

  function gaze_tablet_display() {
    message "${PROBLEM_COLOR}---{ $2: $3 }---${DEFAULT_COLOR}"
    if [[ -d $1 ]]; then
      message "Not a file, skipping ..."
    elif [[ -s $1 && $(file -b --mime-encoding $1) == binary ]]; then
      message "Binary file, skipping ..."
    else
      PAGER=cat show_file "$1" no "$3 is missing or empty"
    fi
  }
  function gaze_tablet_sub() {
    local command=$1
    local cat_file=${command}_file
    tablet_get_$command $spell_directory ${cat_file}
    gaze_tablet_display "${!cat_file}" "$spell" "$command"
  }

  case $command in
    info)
      tablet_get_section_name $spell_directory section_name
      tablet_get_version $spell_directory version
      tablet_get_patchlevel $spell_directory patchlevel
      tablet_get_security_patch $spell_directory security_patch
      tablet_get_build_api $spell_directory build_api
      # not in all tablets yet
      tablet_get_grimoire_name $spell_directory grimoire_name
      # basic information (section & version)
      message "${MESSAGE_COLOR}grimoire / section / spell: ${SPELL_COLOR}" \
              "$grimoire_name / $section_name / $spell${DEFAULT_COLOR}"
      message "${MESSAGE_COLOR}version / patchlevel / security patchlevel:${VERSION_COLOR} $version /" \
              "$patchlevel / $security_patch${DEFAULT_COLOR}"
      message "${MESSAGE_COLOR}Build API:${VERSION_COLOR} $build_api${DEFAULT_COLOR}"
    ;;
    depends)
      gaze_tablet_sub depends
    ;;
    spell_config)
      gaze_tablet_sub persistent_config
    ;;
    sub_depends)
      gaze_tablet_sub sub_depends
    ;;
    rsub_depends)
      gaze_tablet_sub rsub_depends
    ;;
    roots)
      gaze_tablet_sub roots
    ;;
    spell-files)
      for file in $spell_directory/spell/* ;do
        gaze_tablet_display "$file" "$spell" "${file##*/}"
      done
    ;;
    dirs)
      message "${MESSAGE_COLOR}Tablet dir:${DEFAULT_COLOR} $spell_directory"
      message "${MESSAGE_COLOR}Grimoire dir:${DEFAULT_COLOR} $spell_directory/grimoire"
      message "${MESSAGE_COLOR}Section dir:${DEFAULT_COLOR} $spell_directory/section"
      message "${MESSAGE_COLOR}Spell dir:${DEFAULT_COLOR} $spell_directory/spell"
    ;;
    all)
      gaze_tablet $spell info
      gaze_tablet_sub depends
      gaze_tablet_sub persistent_config
      gaze_tablet_sub rsub_depends
      gaze_tablet_sub sub_depends
      gaze_tablet_sub roots
      gaze_tablet $spell spell-files
      gaze_tablet $spell dirs
    ;;
    *)
      gaze_tablet $spell info
      gaze_tablet_sub depends
      gaze_tablet_sub persistent_config
      gaze_tablet_sub rsub_depends
      gaze_tablet_sub sub_depends
    ;;
  esac

}


#---------------------------------------------------------------------
##
## displays various information about a Source Mage system
##
#---------------------------------------------------------------------
function gaze_system_info()
{
  local base_system
  local cur_spell
  local section
  local version
  local variable
  local mirror
  local idx
  local grimoire

  #---
  ## Section: ISO VERSION
  #---

  message -n "${PROBLEM_COLOR}--------------------{"
  message -n "Section:         ISO VERSION"
  message    "}--------------------${DEFAULT_COLOR}"

  if [[ -e /etc/sourcemage-release ]]
  then
    cat /etc/sourcemage-release | sed '/^$/d'
  elif [[ -e /etc/smgl.iso ]]
  then
    cat /etc/smgl.iso | sed '/^$/d'
  else
    message -n "${MESSAGE_COLOR}Couldn't determine what was used to install "
    message -n "this system. Consider adding some information to "
    message    "/etc/sourcemage-release${DEFAULT_COLOR}"
  fi

  #---
  ## Section: UNAME
  #---

  message -n "${PROBLEM_COLOR}--------------------{"
  message -n "Section:               UNAME"
  message    "}--------------------${DEFAULT_COLOR}"

  uname -a

  #---
  ## Section: BASESYSTEM
  #---

  message -n "${PROBLEM_COLOR}--------------------{"
  message -n "Section:          BASESYSTEM"
  message    "}--------------------${DEFAULT_COLOR}"

  #---
  ## Need a list of the base spell and ALL of it's DIRECT
  ## depends(what's in DEPENDS)
  ## base_system="$(gaze dependencies basesystem 2 | sed
  ## -e "s/()//" -e 's/ (depends)//' -e 's/ (optional)//' | tr "\n" " " )"
  #---

  version="$(figure_installed basesystem)"
  section="$(codex_get_spell_section_name basesystem)"
  message -n "${MESSAGE_COLOR}${section}/basesystem:\t"
  message    "${QUERY_COLOR}${version}${DEFAULT_COLOR}\n"

  compute_installed_depends on_down_deps x on
  compute_installed_depends off_down_deps x off
  {
  for curr_spell in $(hash_get on_down_deps basesystem)
  do
    version="$(figure_installed $curr_spell)"
    section="$(codex_get_spell_section_name $curr_spell)"
    message -n "${MESSAGE_COLOR}${section}/${curr_spell}:\t"
    message    "${QUERY_COLOR}${version}${DEFAULT_COLOR}"
  done
  for curr_spell in $(hash_get off_down_deps basesystem)
  do
    version="$(figure_installed $curr_spell)"
    section="$(codex_get_spell_section_name $curr_spell)"
    message -n "${MESSAGE_COLOR}${section}/${curr_spell}:\t"
    message    "${QUERY_COLOR}${version} (disabled)${DEFAULT_COLOR}"
  done
  } | sort

  #---
  ## Section: CODEX
  #---

  message -n "${PROBLEM_COLOR}--------------------{"
  message -n "Section:               CODEX"
  message    "}--------------------${DEFAULT_COLOR}"

  let idx=0
  for grimoire in $(codex_get_all_grimoires)
  do
    message "${QUERY_COLOR} [$idx]: $(smgl_basename "$grimoire"):${DEFAULT_COLOR}" \
            "${MESSAGE_COLOR}$grimoire${DEFAULT_COLOR}"
    let idx+=1
  done

  #---
  ## Section: SORCERY CONFIG
  #---

  message -n "${PROBLEM_COLOR}--------------------{"
  message -n "Section:      SORCERY CONFIG"
  message    "}--------------------${DEFAULT_COLOR}"

  for variable in PROMPT_DELAY DOWNLOAD_RATE PATCH SOUND SORCERER CABAL \
                  NICE SORCERY_BRANCH DEF_INSTALL_INIT DEF_ENABLE_INIT \
                  DEF_INSTALL_XINETD DEF_ENABLE_XINETD DEF_INIT_VS_XINETD \
                  COMPRESSBIN EXTENSION URL_HTTP_FTP_TIMEOUT MD5SUM_DL \
                  GPG_VERIFY_SPELL_LEVEL ARCHIVE AUTOFIX UPDATEFIX AUTOPRUNE \
                  GATHER_DOCS MAIL_REPORTS VIEW_REPORTS PRESERVE SUSTAIN \
                  TMPFS VOYEUR REAP STORE_CONF_LOG NET_SELECT CONFIG_LOC \
                  CLEAN_SOURCE CROSS_INSTALL SET_TERM_TITLE SCREEN \
                  DEBUG SUPER_DEBUG BUILD_DIRECTORY
  do
    message -n "${MESSAGE_COLOR}$variable="
    message    "${QUERY_COLOR}\"${!variable}\"${DEFAULT_COLOR}"
  done

  #---
  ## Section: STATE CONFIG
  #---

  message -n "${PROBLEM_COLOR}--------------------{"
  message -n "Section:        STATE CONFIG"
  message    "}--------------------${DEFAULT_COLOR}"

  for variable in INSTALL_ROOT STATE_ROOT INSTALL_CACHE TRACK_ROOT
  do
    message -n "${MESSAGE_COLOR}$variable="
    message    "${QUERY_COLOR}\"${!variable}\"${DEFAULT_COLOR}"
  done

  #---
  ## Section: COMPILER CONFIG
  #---

  message -n "${PROBLEM_COLOR}--------------------{"
  message -n "Section:     COMPILER CONFIG"
  message    "}--------------------${DEFAULT_COLOR}"

  message -n "${MESSAGE_COLOR}SMGL_COMPAT_ARCHS=${DEFAULT_COLOR}"
  for each in ${SMGL_COMPAT_ARCHS[@]}
  do
    message -n "${QUERY_COLOR}${each}${DEFAULT_COLOR}/"
  done
  message -n "\n"

  for variable in ARCHITECTURE OPTIMIZATIONS CUSTOM_CFLAGS CUSTOM_CXXFLAGS \
                  CUSTOM_LDFLAGS CFLAGS CXXFLAGS LDFLAGS HOST CCACHE \
                  DISTCC_HOSTS JOBS_PER_HOST MAKE_NJOBS CCACHE_DIR
  do
    message -n "${MESSAGE_COLOR}$variable="
    message    "${QUERY_COLOR}\"${!variable}\"${DEFAULT_COLOR}"
  done

  #---
  ## Section: VERIFICATION CONFIG
  #---

  message -n "${PROBLEM_COLOR}--------------------{"
  message -n "Section: VERIFICATION CONFIG"
  message    "}--------------------${DEFAULT_COLOR}"

  for variable in VRF_ALLOWED_LEVELS VRF_ALLOW_NEW_LEVELS VRF_ALLOWED_HASHES \
                  VRF_ALLOW_NEW_HASHES GPG_VERIFY_SORCERY GPG_VERIFY_GRIMOIRE
  do
    message -n "${MESSAGE_COLOR}$variable="
    message    "${QUERY_COLOR}\"${!variable}\"${DEFAULT_COLOR}"
  done

  #---
  ## Section: CLEANSE CONFIG
  #---

  message -n "${PROBLEM_COLOR}--------------------{"
  message -n "Section:      CLEANSE CONFIG"
  message    "}--------------------${DEFAULT_COLOR}"

  for variable in FIND_CHECK MD5SUM_CHECK LDD_CHECK SYM_CHECK
  do
    message -n "${MESSAGE_COLOR}$variable="
    message    "${QUERY_COLOR}\"${!variable}\"${DEFAULT_COLOR}"
  done

  #---
  ## Section: DISPEL CONFIG
  #---

  message -n "${PROBLEM_COLOR}--------------------{"
  message -n "Section:       DISPEL CONFIG"
  message    "}--------------------${DEFAULT_COLOR}"

  for variable in ORPHAN_MENU_DEFAULT NONORPHAN_MENU_DEFAULT \
                  RECAST_PARENT_MENU_DEFAULT DISPEL_PARENT_MENU_DEFAULT
  do
    message -n "${MESSAGE_COLOR}$variable="
    message    "${QUERY_COLOR}\"${!variable}\"${DEFAULT_COLOR}"
  done

  #---
  ## Section: LOCALE CONFIG
  #---

  message -n "${PROBLEM_COLOR}--------------------{"
  message -n "Section:       LOCALE CONFIG"
  message    "}--------------------${DEFAULT_COLOR}"

  for variable in LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY \
                  LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE \
                  LC_MEASUREMENT LC_IDENTIFICATION LC_ALL
  do
    if [[ ! -z ${!variable} ]]
    then
      message -n "${MESSAGE_COLOR}$variable="
      message    "${QUERY_COLOR}\"${!variable}\"${DEFAULT_COLOR}"
    fi
  done

  #---
  ## Section: FACILITIES
  #---

  message -n "${PROBLEM_COLOR}--------------------{"
  message -n "Section:          FACILITIES"
  message    "}--------------------${DEFAULT_COLOR}"

  cat /etc/sysconfig/facilities | sed -e '/^$/d' -e '/^#.*$/d'

  #---
  ## Section: MIRRORS
  #---

  message -n "${PROBLEM_COLOR}--------------------{"
  message -n "Section:             MIRRORS"
  message    "}--------------------${DEFAULT_COLOR}"

  for mirror in APACHE_URL CTAN_URL GNOME_URL GNU_URL KDE_URL KERNEL_URL \
                PERL_CPAN_URL SORCERY_URL SOURCEFORGE_URL XFREE86_URL CODEX_URL
  do
    message -n "${MESSAGE_COLOR}$mirror="
    message    "${QUERY_COLOR}\"${!mirror}\"${DEFAULT_COLOR}"
  done

}

#---------------------------------------------------------------------
##
## prints all spells of a given status.
## @param status - what are we looking for
## @param describe - how is that staus described in english
##
#---------------------------------------------------------------------
function gaze_show_spells_by_status () {
    message -n "${MESSAGE_COLOR}The following spells are set to"
    message -n "${DEFAULT_COLOR} $2:"
    message    "${SPELL_COLOR}"
    get_all_spells_with_status $1 | sort | maybe_column
    message -n "${DEFAULT_COLOR}"
}

#---------------------------------------------------------------------
##
## Display the time spells took to compile and install. If gaze is in
## silent mode, pad all the times as needed.
##
## @param Type (optional) - tells which time calculation to use
## @param Spell
## @param ...
##
#---------------------------------------------------------------------
function gaze_time() {

  local diff time sum=0 err_sum=() n=0 spell type
  if [[ $1 == -* ]]; then
    type=$1
    shift
    if [[ $type == --full ]]; then
      gaze_time_full "$@"
      return
    fi
  fi

  for spell in "$@"; do
    diff=$(compute_cast_time $spell $type)
    if [[ -z $diff ]]; then
      message "${SPELL_COLOR}$spell$PROBLEM_COLOR wasn't cast yet at all!" \
        "${DEFAULT_COLOR}"
      continue
    fi
    if [[ ${diff% *} == $diff ]]; then
      (( sum += $diff ))
    else
      (( sum += ${diff% *}, n++ )) # we'll count the error separately
      err_sum[n]=${diff#* }
    fi

    if [[ $GAZE_VERBOSE != false ]]; then
      message -n "Casting ${SPELL_COLOR}$spell$DEFAULT_COLOR took "
      pretty_print_time $diff
    else
      echo "$spell:$diff"
    fi
  done

  if [[ -n $2 ]]; then
    message -n "${MESSAGE_COLOR}Total time:$DEFAULT_COLOR "
    if [[ $GAZE_VERBOSE != false ]]; then
      pretty_print_time $sum $(compute_total_error "${err_sum[@]}")
    else
      echo $sum $(compute_total_error "${err_sum[@]}")
    fi
  fi
}

#---------------------------------------------------------------------
##
## Display the time spells took to compile and install. If gaze is in
## silent mode, pad all the times as needed. Prints all the available
## times.
##
## @param Spell
## @param ...
##
#---------------------------------------------------------------------
function gaze_time_full() {
  local spell

  for spell in "$@"; do
    compute_all_cast_times $spell $GAZE_VERBOSE
    if [[ $? != 0 ]]; then
      message "${SPELL_COLOR}$spell$PROBLEM_COLOR wasn't cast yet at all!" \
        "${DEFAULT_COLOR}"
      continue
    fi
  done
}

#---------------------------------------------------------------------
##
## Display the time all installed spells took to compile and install.
## If --no-orphans is passed, they are skipped.
##
## @param orphans (optional) - skip orphans
## @param type - see gaze_time
##
#---------------------------------------------------------------------
function gaze_time_system() {
  local type orphans

  while [[ $1 == -* ]]; do
    if [[ $1 == --no-orphans ]]; then
      orphans=no
    else
      type=$1
    fi
    shift
  done

  if [[ $orphans == no ]]; then
    gaze_time $type $(show_non_orphans | sort -u)
  else
    gaze_time $type $(get_all_spells_with_status ok | sort)
  fi
}

parse()  {

  # Maintain "TMP_DIR is always set as a global" invariant in the case of
  # non-root users, this leaves vague security holes but they're limited
  # to files the non-root user can access.
  # a future goal is to make mk_tmp_dirs work for regular users too...
  if  [  "$UID"  -gt  0  ];  then
    export TMP_DIR=/tmp
  else
    mk_tmp_dirs gaze
  fi

  [[ $UID != 0 ]] && test "$NICE" -lt 0 && NICE=0
  renice $NICE -p $$ >/dev/null

  while [[ -n "$1" ]] && [[ ${1:0:1} == "-" ]] ; do
    case $1 in
      -q) GAZE_VERBOSE=false
          PAGER=cat
          shift
          ;;
      -g) for grimoire in $2; do
            if ! codex_find_grimoire $grimoire >/dev/null; then
              message "${PROBLEM_COLOR}No such grimoire: " \
                      "${DEFAULT_COLOR}$grimoire"
              return 1
            fi
            codex_set_grimoires $2
          done
          shift 2
          ;;
      *) help ; exit ;;
    esac
  done


  SPELL=$2
  SECTION=$2
  VERSION=`installed_version  $SPELL`

  case  $1  in

        # Spell components. In alphabetical order.
           BUILD)  show_spell_component $1 $2            ;;
       CONFIGURE)  show_spell_component $1 $2            ;;
       CONFLICTS)  show_spell_component $1 $2            ;;
         DETAILS)  show_spell_component $1 $2            ;;
         DEPENDS)  show_spell_component $1 $2            ;;
        DOWNLOAD)  show_spell_component $1 $2            ;;
           FINAL)  show_spell_component $1 $2            ;;
         HISTORY)  show_spell_component $1 $2            ;;
         INSTALL)  show_spell_component $1 $2            ;;
  INSTALL_EXTRAS)  show_spell_component $1 $2            ;;
           PATCH)  show_spell_component $1 $2            ;;
      POST_BUILD)  show_spell_component $1 $2            ;;
    POST_INSTALL)  show_spell_component $1 $2            ;;
     POST_REMOVE)  show_spell_component $1 $2            ;;
  POST_RESURRECT)  show_spell_component $1 $2            ;;
       PRE_BUILD)  show_spell_component $1 $2            ;;
     PRE_INSTALL)  show_spell_component $1 $2            ;;
      PRE_REMOVE)  show_spell_component $1 $2            ;;
   PRE_RESURRECT)  show_spell_component $1 $2            ;;
 PRE_SUB_DEPENDS)  show_spell_component $1 $2            ;;
         PREPARE)  show_spell_component $1 $2            ;;
        PROVIDES)  show_spell_component $1 $2            ;;
        SECURITY)  show_spell_component $1 $2            ;;
     SUB_DEPENDS)  show_spell_component $1 $2            ;;
        TRANSFER)  show_spell_component $1 $2            ;;
   TRIGGER_CHECK)  show_spell_component $1 $2            ;;
        TRIGGERS)  show_spell_component $1 $2            ;;
     UP_TRIGGERS)  show_spell_component $1 $2            ;;

        # Other options
            html)  shift; gaze_catalog_html $@           ;;
          export)  export_snapshot "$(mk_snapshot_filename)" ;;
          import)  shift; import_snapshot "$@"           ;;
         section)  shift; gaze_show_section $@           ;;
         version)  shift; gaze_show_version $@           ;;
        versions)  shift; gaze_show_versions $@          ;;
     patchlevels)  shift; gaze_show_patchlevels $@       ;;
         license)  shift; gaze_show_license $@           ;;
           alien)  alien                                 ;;
     system-info)  gaze_system_info                      ;;
          tablet)  shift; gaze_tablet $1 $2              ;;
        activity)  display $ACTIVITY_LOG                 ;;
            from)  shift; show_from "$@"                 ;;
           newer)  newer             $2                  ;;
           older)  older             $2                  ;;
         sources)  sources           $SPELL              ;;
     source_urls)  source_urls       $SPELL              ;;
        grimoire)  shift; gaze_catalog $@                ;;
       grimoires)  gaze_show_grimoires                   ;;
          search)  shift; gaze_search "$@"               ;;
        provides)  shift; gaze_provides $@               ;;
         depends)  shift; gaze_show_depends  "$@"        ;;
    dependencies)  shift; gaze_show_dependencies  "$@"   ;;
         orphans)  show_orphans | sort                   ;;
         history)  show_spell_component HISTORY  "$2"    ;;
     website|url)  shift; gaze_show_website           $@ ;;
      maintainer)  shift; show_maintainer             $@ ;;
       installed)  shift; gaze_show_installed         $@ ;;
       show-held)  gaze_show_spells_by_status held hold  ;;
     show-exiled)  gaze_show_spells_by_status exiled exiled ;;
           short)  shift; gaze_show_short_description $@ ;;
            what)  shift; gaze_show_long_description  $@ ;;
           where)  shift; gaze_show_where             $@ ;;
            size)  shift; gaze_show_size              $@ ;;
       checkmd5s)  shift; gaze_md5check               $@ ;;
            time)  shift; gaze_time                   $@ ;;
     time-system)  shift; gaze_time_system            $@ ;;
    compile)  if  [  -n  "$3"        ];  then
                  VERSION=$3
              elif  [  -z  "$VERSION"  ];  then
                  codex_set_current_spell_by_name  $2
              fi
              display  $COMPILE_LOGS/$SPELL-$VERSION$EXTENSION   \
                       "Compile log for $SPELL-$VERSION does not exist"
              ;;

        install) [[ -n $3 ]] && VERSION="$3"
                 gaze_install $SPELL $VERSION ;;
   install-full) [[ -n $3 ]] && VERSION="$3"
                 gaze_install $SPELL $VERSION full ;;
  install-spell) [[ -n $3 ]] && VERSION="$3"
                 gaze_install $SPELL $VERSION spell ;;

    sum)  [  -n  "$SPELL"  ]                         &&
          checksum  "$INSTALL_LOGS/$SPELL-$VERSION"  ||
          checksum  "$INSTALL_LOGS/*"
          ;;


    md5sum)  [  -n  "$SPELL"  ]                             &&
             md5sum_files  "$INSTALL_LOGS/$SPELL-$VERSION"  ||
             md5sum_files  "$INSTALL_LOGS/*"
             ;;

   voyeur)  shift  1;  gaze_activate_voyeur  $@  ;;

 install-queue)  if [[ -s $INSTALL_QUEUE ]]; then
                   $PAGER $INSTALL_QUEUE
                 else
                   message "Install queue does not exist or is empty"
                 fi
                 ;;

  remove-queue)  display  $REMOVE_QUEUE   "Remove queue does not exist"   ;;

             *)  help  ;;

  esac

  # dont put code here unless you save the return value from the case/esac code

}

. /etc/sorcery/config
if  [  $#  == 0  ];  then
  help  |  $PAGER
else
  trap exit PIPE
  parse  "$@"
  rc=$?
  if  [  ${TMP_DIR:0:13} ==  "/tmp/sorcery/"  ];  then
    cleanup_tmp_dir $TMP_DIR
  fi
  exit $rc
fi


#---------------------------------------------------------------------
##=back
##
##=head1 LICENSE
##
## This software is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This software is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this software; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
##
#---------------------------------------------------------------------
