#!/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            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           Views an install log, and sorcery log files for to the spell.
install-full    spell           Views an install log including all sorcery state files.
install-spell   spell           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
export                          Makes snapshot of box's configuration.
import          snapshot        Restores snapshot.

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] 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
                                 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

show-held                        Shows all held spells.

show-exiled                      Shows all exiled spells.

EOF
}

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

#-----
## Make building multiple identical systems easy with exporint of a
## snapshot of the current state.
## <p>Is this actualy used for anything still? Does it work?
#-----
function export_snapshot()  {

  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
  cp  -a  /etc           $SOURCE_DIRECTORY
  cp  -a  $CONFIG_CACHE  $SOURCE_DIRECTORY

  for  LINE  in  `cat  $SPELL_STATUS`;  do
    SPELL=`echo  $LINE  |  cut  -d  :  -f1`
     STATUS=`echo  $LINE  |  cut  -d  :  -f2`
    if  [  "$STATUS"  ==  "installed"  ];  then
      echo  $SPELL  >>  /usr/src/snapshot/install
    fi
  done

  SNAPSHOT="/root/snapshot-$HOSTNAME-`date  -u  +%Y%m%d`.tar$EXTENSION"

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

  rm_source_dir          $SOURCE_DIRECTORY
  echo  "$SNAPSHOT created."

}

#-----
## To make the <@function export_snapshot> actualy be useful, an import
## is quite handy.
## @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

          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

}

#-----
## 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 != 0 ]] ; 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 != 0 ]] &&
  message  "Discovering installed files..."
  { cat $SORCERY_INSTALL_LOG ; find $INSTALL_LOGS/ -type f|xargs cat ; }  |
    files  |  sort  >  $TMP_DIR/gaze.known

  [[ $GAZE_VERBOSE != 0 ]] &&
  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 != 0 ]] && echo  "Sorcery Grimoire for `date  -u`"

  if [ $grimoire ]; then
        echo "Grimoire: " $(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 != 0 ]]; then
      echo
      echo  "-------------------------------------------------"
      echo  "SECTION: $(  basename  $SECTION  )"
      echo  "-------------------------------------------------"
    else
      echo
      echo  "SECTION: $(  basename  $SECTION  )"
    fi
    for  spell  in  `codex_get_spells_in_section $SECTION`;  do
      echo `basename $spell` #keeps head from breaking pipes
      ((  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: " $(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>$( 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()  {

  if  [  -s  "$1"  ];  then
    case  "$(file  -b  $1)"  in
      *text)       cat  $1  |  $PAGER  ;;
      bzip2*)     bzcat  $1  |  $PAGER  ;;
      gzip*)   gzip -cd  $1  |  $PAGER  ;;
      *) message "Unknown file type."
      return 1 ;;
    esac
  else
    message  "$2" 1>&2
    false
  fi

}

#-----
## 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 Search string
## @Stdout grep results
#-----
function show_from()  {

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

  cd $INSTALL_LOGS
  find . -printf "%f\n" | xargs grep "`esc_str $1`$" |
  seperate_state_files /dev/stdin /dev/stdout /dev/null | sort

}

#-----
## 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 -il -- "${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

    for pattern in "$@"; do
        for grimoire in $(codex_get_all_grimoires); do
            for spell in $(
    grep_find_grimoire $grimoire "DETAILS" "SHORT=.*${pattern}"
                        ); do

                spellname=$(basename $(dirname $spell))
                if [[ $GAZE_VERBOSE == 0 ]]; 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

  if ! [[ $GAZE_VERBOSE == 0 ]] ; 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 -il "${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
        if [[ $GAZE_VERBOSE == 0 ]]; then
          basename $(dirname $file)
        else
          clear_line
          echo "$pattern ->  $(basename $(dirname $file) ) ${SEARCH_RESULTS}"
        fi
      fi
    done
  done

  if ! [ "$GAZE_VERBOSE" == "0" ]; 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 == 0 ]] &&
        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()  {
  compute_reverse_installed_depends my_hash
  for each in $(get_all_spells_with_status 'installed';get_all_spells_with_status 'held'); do
  if [[ ! $(hash_get my_hash $each) ]] ; then
    echo "$each"
  fi
  done|sort
}




#---------------------------------------------------------------------
##
## 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 == 0 ]] &&
        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
  local SPELL_DIRECTORY=
  local GRIMOIRE=
  local GRIMOIRES=
  local ECHO_INSTALLED=1
  local GRIMOIRE_NAME

  if ! codex_does_spell_exist $SPELL
  then return 1
  fi

  local INSTALLED=`installed_version $SPELL`

  GRIMOIRES=$(codex_get_all_grimoires)

  (

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

  for GRIMOIRE in $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|$SECTION|$SPELL|$VERSION|${INSTALLED:="-"}"
        ECHO_INSTALLED=0
      else
        echo  "$GRIMOIRE_NAME|$SECTION|$SPELL|$VERSION|-"
      fi

    else
      echo "$(basename $GRIMOIRE)|-|-|-|-"
    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 "$(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 == 0 ]] &&  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 == 0 ]] &&
      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 == 0 ]] &&
        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 == 0 ]]; 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 == 0 ]] &&
        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 == 0 ]]; 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 == 0 ]]; 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
    while true; do
        if [[ $1 == --fast ]] ; then
            fast=yes
            shift
            continue
        fi
        break
    done
    local spell=$1
    codex_does_spell_exist "$spell"  &&
    if [[ "$GAZE_VERBOSE" == 0 ]] || [[ "$fast" ]]; then
      show_up_depends "$1" "$2" "$fast"
    else
      show_up_depends  "$1" "$2" "verbose"|
      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 space an installed spell uses
## @param Spell
## @param ...
##
#-----
function gaze_show_size () {
    local spell each
    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
}

#---------------------------------------------------------------------
##
## 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]: $(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}"
}

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=0
          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                       ;;
          import)  import_snapshot   $2                  ;;
         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                      ;;
        activity)  display $ACTIVITY_LOG                 ;;
            from)  show_from         $2                  ;;
           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                          ;;
         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               $@ ;;


    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) gaze_install $SPELL $VERSION ;;
   install-full) gaze_install $SPELL $VERSION full ;;
  install-spell) 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
##
#---------------------------------------------------------------------
