#!/bin/bash
#---------------------------------------------------------------------
## @Synopsis cast is the spell installation utility. It can be called by the user or by sorcery
## @Copyright Original version Copyright 2001 by Kyle Sallee
## @Copyright Some parts copyright 2002 Anders Bruun Olsen et al
## @Copyright Other additions/corrections Copyright 2002 by the Source Mage Team
## Script to cast spells.
#---------------------------------------------------------------------

#-----
## Help... hmm... I wonder what it does...
#-----
function help() {

  cat  <<  EOF

Cast installs single or multiple spells

Example:          cast  nano hdparm sudo
Usage:            cast  [parameters]  [spell]

Optional Parameters:

       --cflags                 Custom CFLAGS
       --cxxflags               Custom CXXFLAGS
       --ldflags                Custom LDFLAGS
       --no-opts                Turn off setting optimization flags, except
                                for those found in --cflags, --cxxflags and
                                --ldflags

-V [on|off]                     Override \$VOYEUR setting

-f  |  --fix                    Discover and fix broken spells
-n  |  --nofix                  Discover, but do not fix broken spells
                                (Both deprecated, use cleanse instead)

-d  |  --download               Force download of sources (overwrite existing
                                files)

-s                              Download all given spells before compiling
       --deps                   Configure spells and determine dependencies,
                                but do not cast.

-c  |  --compile                Recompile the spells (dont install from cache).
-r  |  --reconfigure            Select new dependencies for spells (implies -c)

-R  |  --recast-down            Recast depended-upon spells, even if they are
                                already installed...
-B  |  --recast-up              Recast dependent spells, even if they are
                                already installed...

       --from   directory       Specify an alternate for $SOURCE_CACHE
       --url    URL             Specify an alternate download URL

       --pam                    Re-casts all installed spells that
                                can use Linux-PAM

       --queue                  Casts all spells listed in $INSTALL_QUEUE

EOF

  exit  1

}

#---------------------------------------------------------------------
## @Aguments Arguments of cast
## @Globals DEPS_ONLY RECONFIGURE COMPILE 
## @Globals FORCE_DOWNLOAD SOURCE_CACHE SILENT FIX NOFIX SEPARATE
## @Globals BASE_URL INSTALL_QUEUE 
##
## Sets these globals except INSTALL_QUEUE according to cast's 
## arguments.
## Requires some user interaction if --queue is given and starts
## another cast with INSTALL_QUEUE's content as parameter.
#---------------------------------------------------------------------
function process_parameters()  {

  while  [  -n  "$1"  ];  do

    if  echo  "" $1  |  grep  -q  "^ -";  then

      case  $1  in

            --cflags)  export OVERRIDE_CFLAGS="$2";    COMPILE="-c"; shift 2  ;;
          --cxxflags)  export OVERRIDE_CXXFLAGS="$2";  COMPILE="-c"; shift 2  ;;
           --ldflags)  export OVERRIDE_LDFLAGS="$2";   COMPILE="-c"; shift 2  ;;
           --no-opts)  export NO_OPTIMIZATION_FLAGS=1; COMPILE="-c"; shift 1  ;;
                  -V)  export VOYEUR_OVERRIDE="$2";                  shift 2  ;;
              --deps)  export  DEPS_ONLY="$1";                       shift 1  ;;
    -r|--reconfigure)  RECONFIGURE="$1"; COMPILE="-c";               shift 1  ;;
    -R|--recast-down)  RECAST_DOWN="$1";                             shift 1  ;;
      -B|--recast-up)  RECAST_UP="$1";                               shift 1  ;;
        -c|--compile)  COMPILE="$1";                                 shift 1  ;;
       -d|--download)  export  FORCE_DOWNLOAD="$1"; COMPILE="-c";    shift 1  ;;
              --from)  export  SOURCE_CACHE=$2;                      shift 2  ;;
            --silent)  SILENT="$1";                                  shift 1  ;;
            -f|--fix)  export  FIX="$1";                             shift 1  ;;
          -n|--nofix)  export  FIX="--fix"                         
                       export  NOFIX="$1";                           shift 1  ;;
                  -s)  export  SEPARATE="$1";                        shift 1  ;;
               --url)  export  BASE_URL="$2";                        shift 2  ;;
               --pam)  cast  -c  `find_pam_aware` ;                  shift 1  ;;
             --queue)  
                       if query "Would you like review the queue history for each spell?" n ; then
                         sorcery review-queue
                       fi

                       if  [  -s $INSTALL_QUEUE  ]; then
                         message -n "${MESSAGE_COLOR}Casting install queue..."
                         message    "${DEFAULT_COLOR}"

                         # remove possible empty lines from queue.
                         grep -Ev '^$' $INSTALL_QUEUE >"$INSTALL_QUEUE.new"
                         rm -f "$INSTALL_QUEUE"
                         mv "$INSTALL_QUEUE.new" "$INSTALL_QUEUE"

                         # cast the queue.
                         # SILENT and RECONFIGURE may be empty, they
                         # must be at the end or it will confuse parameter
                         # parsing
                         cast -c `cat $INSTALL_QUEUE 2>/dev/null` "$SILENT" "$RECONFIGURE"
            
                         # report spells still in queue.
                         if  [  -s  $INSTALL_QUEUE  ] ; then
                           message "${MESSAGE_COLOR}The install queue is not empty, "
                           message "it still contains the following spells: "
                           message "---------------------------------${PROBLEM_COLOR}"
                           message "`cat $INSTALL_QUEUE 2>/dev/null`"
                           message "${DEFAULT_COLOR}"
                         fi
                       fi;                               
                       shift 1                                ;;
                   *)  help                                   ;;
      esac

    else

      shift
 
   fi

  done

}

#---------------------------------------------------------------------
## @Arguments cast's arguments
## Goes through arguments and prints spells or parameters that are no
## switches rather.
#---------------------------------------------------------------------
function strip_parameters()  {

  while  [  -n  "$1"  ];  do

    if  echo  "" $1  |  grep  -q  "^ -";  then

      case  $1  in

                  --deps)  shift 1  ;;
                --cflags)  shift 2  ;;
              --cxxflags)  shift 2  ;;
               --ldflags)  shift 2  ;;
               --no-opts)  shift 1  ;;
                      -V)  shift 2  ;;
        -R|--recast-down)  shift 1  ;;
          -B|--recast-up)  shift 1  ;;
        -r|--reconfigure)  shift 1  ;;
                  --from)  shift 2  ;;
                --silent)  shift 1  ;;
                -f|--fix)  shift 1  ;;
              -n|--nofix)  shift 1  ;;
            -c|--compile)  shift 1  ;;
           -d|--download)  shift 1  ;;
                      -s)  shift 1  ;;
                   --url)  shift 2  ;;
                   --pam)  shift 1  ;;
                 --queue)  shift 1  ;;
                       *)  shift 1  ;;

      esac

    else

      echo  $1
      shift
 
   fi

  done

}

#---------------------------------------------------------------------
## Cast a single spell. When this function is called, all dependencies
## have been taken care of and we are allowed to cast this.
## @Globals SPELL
#---------------------------------------------------------------------
function cast_spell()  { (

  debug "cast" "Casting spell [$SPELL]"
  set_term_title "Casting spell [$SPELL]"

  run_details 
  load_build_api || return 1

# these both prompt, and prompting should NOT occur at this point
# someday they will get split to a query and action pair (like use_xinetd
# and install_xinetd) (afk 4/10/04)
  run_security  &&
  run_conflicts || return 1

  # show_downloading tail -f's (essentially) the download log as it
  # comes in, or if downloading is complete, cats the download log, in
  # either case it blocks until downloading is complete by the presence of
  # a ${download_log}.done file. If SEPARATE is set, then all downloading
  # is done first, so there is no need to wait for it to complete.
  if [[ ! $SEPARATE ]] ; then
    show_downloading $SPELL
  fi

  verify_sources ||   return 1
  
  # wait for solo casts, to finish and ensure that others can't
  acquire_cast_lock

  # all this needs to reorganized and stuff...later

  IW_LOG="$TMP_DIR/$SPELL.iw"

  #some minor discussion occured about having this, i'll leave it out for now
  activity_log  "cast"  "$SPELL"  "$VERSION"  "start"

  # must declare OPS before sourcing config
  local OPTS
  run_spell_config                            

  # this should probably be moved...
  spell_depends=$(hash_get uncommitted_hash $SPELL)
  test -e $spell_depends && 
  OPTS="$OPTS $(get_depends_options $spell_depends $SPELL)"
  
  # this will run through the whole build process
  run_build_spell
  rc=$?

  # This is the home for anything and everything we do
  # when a phase4 succeeds or fails, no more spreading things out
  # into multiple functions.

  cd /

  pop_install_queue "$SPELL"    

  # hooks back out to the build_api to do whatever needs to be done
  if [ $rc == 0 ] ; then
    run_spell_success
  else
    run_spell_failure $rc
  fi


  unlock_resources "cast" "$SPELL"
  #It's OK to try to release a lock you don't have
  unlock_resources "solo" "cast"

  return $rc

) }

##Removed *_solo functions, Duff 2002/11/01

#---------------------------------------------------------------------
## @Globals SPELLS
## @Stdout User information ("Collating dependencies")
## @Globals SPELL MAKEFILE DEPS_ONLY
##
## Basically only gathers all dependencies and creates the Makefile
## (According to pass_zero it ought to take SPELLS as parameter, but
## it doesn't)
## SPELLS is changed to the dependencies of SPELLS if DEPS_ONLY is specified
## this might effect pass_five
#---------------------------------------------------------------------
function pass_one()  {
  #  This pass does configuration and dependency identification.
  debug "cast" "Starting pass_one()"

  echo -n "Computing previously installed dependencies..."
  compute_installed_depends "already_cast"
  echo
  compute_uninstalled_depends "to_cast" "back_hash" "bad_spells" $SPELLS

  local SPELLS_TO_CAST=$(hash_get_table_fields "to_cast")
  SPELLS=$SPELLS_TO_CAST

  # special case of no spell making it through dependency resolution
  # or if DEPS_ONLY is set, there arent any dependent spells to cast
  if [ -z "$SPELLS_TO_CAST" ] ; then 
    local cannot_cast=$(hash_get_table_fields "bad_spells")
    message "${PROBLEM_COLOR}No spells to cast!${DEFAULT_COLOR}"
    message "${MESSAGE_COLOR}Cannot cast these spells:${DEFAULT_COLOR}"
    message "---------------------------"
    message "${PROBLEM_COLOR}${cannot_cast}" | tr '[:blank:]' '\n' | column 
    message "${DEFAULT_COLOR}"
    exit 1
  fi

  # if only doing the deps, find the dependencies
  #
  # there are two cases, and its not clear which is the case
  # a) cast ALL depends of the spells
  # b) cast the depends which need to be cast (are in the to_cast hash)
  #
  # I think the behavior was intended to be case "b", the extra code for
  # case "a" is below and commented out
  # note: dependency information for all spells if it exists will be in
  # either the to_cast hash or the already_cast hash
  #
  # note: SPELLS/SPELLS_TO_CAST  is not empty due to the check above
  #
  if  [[ "$DEPS_ONLY" ]] ;  then
    local dep_spell
    local TMP_SPELLS=$(
      for spell in $SPELLS_TO_CAST; do
        for dep_spell in $(hash_get to_cast $spell); do
          echo $dep_spell
        done
      done|sort|uniq)
    for spell in $TMP_SPELLS ; do
      if echo $SPELLS_TO_CAST|grep -q $spell; then
        hash_put new_to_cast $spell $(hash_get to_cast $spell)
      # note, if case "a" (describe above) was intended, uncomment the
      # following two lines of code
      # else
      #   hash_put new_to_cast $spell $(hash_get already_cast $spell)
      fi
    done
    SPELLS=$(hash_get_table_fields new_to_cast)
    if [ -z "$SPELLS" ] ; then 
      local parents=$(hash_get_table_fields "to_cast")
      message "${PROBLEM_COLOR}No spells to cast!${DEFAULT_COLOR}"
      message "${MESSAGE_COLOR}None of the spells have dependencies" \
              "to cast:${DEFAULT_COLOR}"
      message "---------------------------"
      message "${PROBLEM_COLOR}${parents}" | tr '[:blank:]' '\n' | column 
      message "${DEFAULT_COLOR}"
      exit 1
    fi
  fi

  message "${MESSAGE_COLOR}Collating dependencies...${DEFAULT_COLOR}"

  if  [[ "$DEPS_ONLY" ]] ;  then  
    local spell dep_spell
    depends_to_Makefile new_to_cast already_cast "$SPELLS" > $MAKEFILE
  else
    depends_to_Makefile to_cast already_cast "$SPELLS" > $MAKEFILE
  fi

  debug "cast" "pass_one, done with SPELLS=$SPELLS"

}

#-----
## Take the depends hashtable and turn it into the Makefile used later
## @param Dependencies of spells to cast
## @param Dependencies of spells not to cast
## @param list of spells to use for the all target. There should be info in
## the first param for all of these. If not things will act strangely,
## but thats not a bug in this function.
#-----
function depends_to_Makefile()
{
  debug "cast" "depends_to_Makefile - $*"

  # This is needed because compute_installed_depends may have
  # stale dependency information compared with the information
  # from compute_uninstalled_depends. So we strip off any depends
  # info from the installed depends hash.
  for i in $( { hash_get_table_fields $1 ; hash_get_table_fields $2; } | sort | uniq -d ); do
    hash_unset "$2" "$i"
  done
  
  [[ $COMPILE ]] && args="-c "
  
  # Spells that are actualy going to be cast
  for i in $( hash_get_table_fields $1 ) ; do
    echo "$i : $(hash_get "$1" "$i")"
    echo -e "\t@bash $0 $args $i"
    echo
  done
  
  #Spells that are already cast
  #NOTE: For recursive recompile cast, make this loop like loop above
  for i in $( hash_get_table_fields $2 ) ; do
    echo "$i : $(hash_get "$2" "$i")"
    echo
  done

  # make will run the all target, which would be the spells we care about
  echo "all : $(echo $3|tr '[:cntrl:]' ' ')"
  echo

  # if dependency rules fail us, match here after everything else
  # has had the chance, and do nothing, instead of exit early...
  echo %:
  echo -e "\t@echo -n"
  echo

  # this caused a rather nasty bug where a file in the current directory
  # had the same name as a spell, and make thought it had already "made"
  # that spell
  local all_spells=$( { hash_get_table_fields $1 ; hash_get_table_fields $2 ; } | tr '[:cntrl:]' ' ')
  echo ".PHONY : all $all_spells"
}


#---------------------------------------------------------------------
## @Arguments Spells to be cast
## @Stdout the "Spells are to be cast" message.
## @Stdin User interface, y or n  
## @Globals SEPARATE
## Asks whether you want to cast the listed spells or not.
## Returns if not. 
## Then it starts pass three and four by calling make.
## Depending on SEPARATE it starts pass three in the background
## or not.
#---------------------------------------------------------------------
function pass_two()  {
  #  This pass downloads required sources.
  #  And starts the make process
  debug "cast" "Starting pass_two()"

  message "${MESSAGE_COLOR}Spells are to be cast:${DEFAULT_COLOR}"
  message "---------------------------"
  message "${SPELL_COLOR}${*}" | tr '[:blank:]' '\n' | column 
  message "${DEFAULT_COLOR}"
  
  if ! query "Do you want to cast these spells?" "y" ; then
    message "Ok, quitting cast. Figure out what you want."
  return 1
  fi

  local REAL_MAKE
  find_make REAL_MAKE || return $?
  
  #make: -k keep going even if there's an error, -s silent, -f <file>
  rm -f $TMP_DIR/pass_three.done # dont return until this file exists
  if  [[  $SEPARATE   ]] ; then
    ( CAST_PASS="three" 
      $REAL_MAKE -j1 -k -f $MAKEFILE $*
      touch $TMP_DIR/pass_three.done
    )
  else
    ( CAST_PASS="three"
      $REAL_MAKE -j1 -k -f $MAKEFILE $*
      touch $TMP_DIR/pass_three.done
    ) &
  fi
  
  debug "cast" "Starting stage four make."
  
  ( CAST_PASS="four" ; $REAL_MAKE -j1 -k -f $MAKEFILE $* )
  
  # in some very bad situations pass four can complete before three, and if
  # we return too soon more bad things can happen, so wait at least a little
  # bit of time before giving up.
  local i
  let i=0
  while ! test -e $TMP_DIR/pass_three.done; do 
    sleep 5
    let i+=5
    [[ $i > 60 ]] && break
  done
  rm $MAKEFILE

}

#---------------------------------------------------------------------
## @param spellname
## @Globals SPELL
## Sets SPELL to the spellname and calls summon_spells with spellname
## as argument. This is equivalent to calling summon, but without the
## overhead.
## (Is being called by make)
#---------------------------------------------------------------------
function pass_three()  {
  debug "cast" "pass_three - $*"
  unset CAST_PASS
  local SPELL=$1
  local download_log=$(get_spell_dl_log $SPELL)
  # check if this is being resurrected and if so, dont summon
  # this will go away when resurrect support and dependency resolution merge
  if ! [[ $COMPILE ]] ; then
    VERSION=$(codex_set_current_spell_by_name $SPELL &> /dev/null;echo $VERSION)
    if [[ $VERSION ]] && can_resurrect $SPELL $VERSION &> /dev/null ; then
      # touch the 'log' file just in case the spell disagreed so cast doesnt
      # hang forever
      echo "pass_three thought that $SPELL was being resurrected" \
               > $download_log 2>/dev/null
      touch ${download_log}.done &>/dev/null
      return
    fi
  fi
  if  [[  $SEPARATE   ]] ; then
    summon_spells "$SPELL"
  else
    touch $download_log
    lock_file   $download_log
    summon_spells "$SPELL" &>  $download_log
    unlock_file   $download_log
  fi
  
  # This is to notify show_downloading/cast_spell that it is done with
  # this source
  touch "${download_log}.done"
}

#---------------------------------------------------------------------
## @param spellname
## @Globals SPELL COMPILE
## Sets SPELL to spellname.
## Calls trigger "pre_cast"
## If COMPILE is not set and it can be resurrected 
## (can_resurrect SPELL) it calls resurrect with SPELL as argument.
## Otherwise it calls cast_spell.
## If resurrect or cast_spell returned 0 it calls trigger "cast"
## (Is being called by make)
#---------------------------------------------------------------------
function pass_four()  {

  debug "cast" "pass_four - $*"
  local do_resurrect=no
  local VERSION
  unset CAST_PASS
  SPELL=$1
  trigger "pre_cast"
  if ! [[ $COMPILE ]] ; then
    # hacky way to get the latest version
    VERSION=$(codex_set_current_spell_by_name $SPELL &> /dev/null;echo $VERSION)
    if [[ ! $VERSION ]] ; then
      message "Cant find spell version for some reason, is $SPELL a spell?"
    else
      can_resurrect $SPELL $VERSION &> /dev/null && do_resurrect=yes
    fi
  fi

  # this is a hacky way to tell what version we're updating from
  # if any, we can use it to find md5 logs for installing config type
  # files, it mostly is here for libresurrect.real_install_config_file
  local OLD_SPELL_VERSION
  spell_ok $SPELL && OLD_SPELL_VERSION=$(installed_version $SPELL)

  local rc
  if [[ "$do_resurrect" == "yes" ]] ; then
    resurrect $SPELL $VERSION
    rc=$?
    # this is here for safety in case resurrect bails out somewhere
    # we didnt expect it to
    unlock_resources "libgrimoire" "install"
    unlock_resources "cast" "$SPELL"
    unlock_resources "solo" "cast"
  else
    cast_spell $*
    rc=$?
  fi

  # We only want to trigger if the cast or resurect completed properly
  [ $rc -eq 0 ] && trigger "cast"
  return $rc
}


#---------------------------------------------------------------------
## @Globals SUCCESS_LIST FAILED_LIST 
## Does report generation.
#---------------------------------------------------------------------
function pass_five()  {

  debug "cast" "Function : pass_five"

  # must exist or we get problems with checks here.
  touch $SUCCESS_LIST
  touch $FAILED_LIST
  touch $CONFLICT_LIST
  
  debug "pass_five" "SUCCESS LIST is : `cat $SUCCESS_LIST 2>/dev/null`"
  debug "pass_five" "FAILED LIST is : `cat $FAILED_LIST 2>/dev/null`"
  debug "pass_five" "CONFLICT LIST is : `cat $CONFLICT_LIST 2>/dev/null`"

  if [ -s $SUCCESS_LIST ] ; then

    message "${MESSAGE_COLOR}Finished processing install requests."
    message ""
    message "Spells installed successfully:"
    message "------------------------------${SPELL_COLOR}"

    for item in `cat $SUCCESS_LIST 2>/dev/null`; do
      message "$item"
    done | column
   
    set_term_title "Casting successfull."
    message "${DEFAULT_COLOR}"

  fi 

  local NOT_CAST
  NOT_CAST=$( { hash_get_table_fields to_cast 
    cat $SUCCESS_LIST
    cat $FAILED_LIST
    } | sort | uniq -u ) # all not caught otherwise
  if [[ "$NOT_CAST" ]] ;then
    message "${DEFAULT_COLOR}" #being paranoid
    message "${MESSAGE_COLOR}Spells that have been dropped:"
    message "------------------------------${QUERY_COLOR}"
    message "$NOT_CAST" | column
    message "${DEFAULT_COLOR}"
  fi

  if  [  -s  $CONFLICT_LIST   ] ; then
    message "${DEFAULT_COLOR}"
    message "${MESSAGE_COLOR}Spells that have been removed due to conflicts:"
    message "-----------------------------------------------${QUERY_COLOR}"
    for item in `cat $CONFLICT_LIST 2>/dev/null`; do
      message "$item"
    done | column
    message "${DEFAULT_COLOR}"
  fi
  
  #
  # To check for failed spells, we only need to see what is remaining in the 
  # install queue.
  #
  if  [  -s  $FAILED_LIST   ] ; then
    
    message "${DEFAULT_COLOR}"
    message "${MESSAGE_COLOR}Spells that encountered problems:"
    message "---------------------------------${PROBLEM_COLOR}"
    
    # for item in $* ; do
    #  if ! ([ -e $SUCCESS_LIST ] && grep -q "^$item$" $SUCCESS_LIST) ; then
    #    message "$item"
    #  fi

    for item in `cat $FAILED_LIST 2>/dev/null`; do
      message "$item"
    done | column

    set_term_title "Casting failed."
    message "${DEFAULT_COLOR}"
    return 1

  fi 
  
  debug "cast" "End of pass_five"

}

#---------------------------------------------------------------------
## @Arguments Spells to cast
## @Globals CAST_PASS
## 
## Starts the passes and sets CAST_PASS accordingly.
#---------------------------------------------------------------------
function pass_zero()  {

  debug "cast" "Starting pass_zero()"
  debug "pass_zero" "Starting passes 1,2,3,4 with : '$*'"
  debug "pass_zero" "   and with spells : '$SPELLS'"
  export  CAST_PASS="one";    pass_one $*  &&
  export  CAST_PASS="two";    pass_two $SPELLS
  #pass_three and _four are hidden inside the makefile
  debug "pass_zero" "Starting pass 5 with: '$@'"
  export  CAST_PASS="five";  pass_five "$@"


}

#---------------------------------------------------------------------
## @STDOUT User information ("Cleaning up as well as I can...")
## That function is being called when the process receives 
## SIGINT. It then calls cleanup.
#---------------------------------------------------------------------
function int_trap()
{
  message "${PROBLEM_COLOR}SIGINT${DEFAULT_COLOR}"
  message "Cleaning up as well as I can..."
  cleanup
  exit 1
}

#---------------------------------------------------------------------
## @Globals RM_AT_END
## RM_AT_END is being set in main.
## Used for cleaning up. Deleting some files and $TMP_DIR.
#---------------------------------------------------------------------
function cleanup() {
  debug "cleanup" "Cleaning up the contents of `cat $RM_AT_END 2>/dev/null`"
  rm $(cat $RM_AT_END 2>/dev/null) $RM_AT_END 2>/dev/null
  cleanup_tmp_dir $TMP_DIR
}

#---------------------------------------------------------------------
## @Arguments arguments of cast
## @Globals FIX RM_AT_END ENV_CACHE CAST_PASS 
## @return 0 always
## Starts prameter processing and casts the given spells.
## The list of given spells is being searched for invalid spells
## which are then being reported. Then the passes are being started
## according to CAST_PASS
#---------------------------------------------------------------------
function main()  {

  debug "cast" "main() - $*"
  local T_SPELLS=""
  process_parameters        "$@"
  SPELLS=`strip_parameters  "$@"`

  if  [[  $FIX  ]];  then
    message "${PROBLEM_COLOR}cast --fix is depreciated and will be" \
            "removed in the next sorcery releae.\nPlease use cleanse --fix" \
            "instead.${DEFAULT_COLOR}"
    exit 1
  else

    for spell in $SPELLS ; do
      codex_does_spell_exist $spell
      if [ $? -eq 0 ] ; then
        T_SPELLS="$T_SPELLS $spell"
      fi
    done
    SPELLS=$T_SPELLS
  
    if ! [[ $SPELLS ]]; then
      return 1
    fi
  
    MAKEFILE="$TMP_DIR/Makefile"
    export ENV_CACHE=${ENV_CACHE:-$TMP_DIR/envCache}
    echo "$SUCCESS_LIST $FAILED_LIST $0 $ENV_CACHE" >> $RM_AT_END
    export RM_AT_END="$RM_AT_END"
    BASE_SPELLS=" $SPELLS "

    case  $CAST_PASS  in
       one)  pass_one    $SPELLS  ;; #Never matches
       two)  pass_two    $SPELLS  ;; #Never matches
     three)  pass_three  $SPELLS  ;; #d/l sources, Never matches
      four)  pass_four   $SPELLS  ;; #real casting, Never matches
      five)  pass_five   $SPELLS  ;; #cast report
         *)  pass_zero   $SPELLS  ;; #start everything
    esac
    local rc=$?
  fi

  return $rc
}


. /etc/sorcery/config
[[ $VOYEUR_OVERRIDE ]] && VOYEUR="$VOYEUR_OVERRIDE"
export TOP_LEVEL=${TOP_LEVEL:-$SHLVL}

if    [  $#      -eq  0  ];  then  help  |  $PAGER

elif  [[  $1 == -h  ]]  ||  [[  $1 == --help  ]] ; then help
elif  [  "$UID"  -gt  0  ];  then

  echo  "Enter the root password, please."
  PARAMS=$(consolidate_params "$@")
  su -c "$0 $PARAMS" root

elif  [  ${0:0:5} !=  "/tmp/"  ];  then

  # Make a nice dir structure to put stuff in, this exits if it fails
  mk_tmp_dirs cast

  if ! [[ $RM_AT_END ]] ; then
    #This stuff is here to make sure a user can't make the file
    # and fill it up with stuff we feel the need to delete
    export RM_AT_END=${RM_AT_END:-"$TMP_DIR/tmplist"}
    touch $RM_AT_END
    chown root:root $RM_AT_END
    chmod 600 $RM_AT_END
    echo -n '' > $RM_AT_END
  fi
  
  export SAFE_CAST=$TMP_DIR/casting.safe
  export SUCCESS_LIST="$TMP_DIR/success_list"
  export FAILED_LIST="$TMP_DIR/failed_list"
  export CONFLICT_LIST="$TMP_DIR/conflict_list"
  lock_file $SAFE_CAST
  
  cp  $0  $SAFE_CAST
  chmod +x $SAFE_CAST
  echo "$SAFE_CAST $FAILED_LIST $SUCCESS_LIST $CONFLICT_LIST" >> $RM_AT_END
  exec bash $SAFE_CAST "$@"
  
else
  if  [[  $NICE != "0"  ]] ; then
    renice $NICE -p $$  >/dev/null
  fi
  trap int_trap INT
  main  "$@"
  rc=$?
  if [ $SHLVL -eq $TOP_LEVEL ] ; then
    unlock_file $SAFE_CAST
    cleanup
  fi
  exit $rc
fi

debug "cast" "exiting..."

#---------------------------------------------------------------------
##=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
##
#---------------------------------------------------------------------

