/var/lib/sorcery/modules/libdepends

     1	#!/bin/bash
     2	#---------------------------------------------------------------------
     3	## @Synopsis Functions for dealing with dependencies as a non-cyclic directed graph. Since that's such a mouthful, it will simply be referred to as a tree, even though it's not.
     4	## @Copyright (C) 2002 The Source Mage Team <http://www.sourcemage.org>
     5	## A spell is represented as a node containing some pieces of data
     6	## seperated by colons.
     7	## spell:dependent spell:on/off:type:casting_flag:is_a_target_flag
     8	## @Contributers Chris Brien (christopher_brien@hotmail.com)
     9	## @Contributers Paul Mahon (pmahon@sourcemage.org)
    10	#---------------------------------------------------------------------
    11	
    12	#
    13	# conceptual function call tree...perhaps this will enlighten sorcery
    14	# students..
    15	#
    16	# compute_uninstalled_depends (the entry point)
    17	#   -> for each spell (this list grows during processing)
    18	#     -> run PREPARE
    19	#     -> run CONFIGURE
    20	#     -> run DEPENDS
    21	#       -> depends|runtime_depends <spell> (external)
    22	#         -> work_depends_spell
    23	#           -> private_common_depends -> libstate.add_depends
    24	#             -> add to NEW_DEPENDS
    25	#             -> libstate.add_depends
    26	#       -> optional_depends|suggest_depends <spell> (external)
    27	#         -> work_optional_depends_spell
    28	#           -> query
    29	#           -> private_common_depends -> libstate.add_depends
    30	#             -> add to NEW_DEPENDS
    31	#             -> libstate.add_depends
    32	#       -> depends|runtime_depends <provider> (external)
    33	#         -> work_depends_provider
    34	#           -> select provider
    35	#           -> private_common_depends -> libstate.add_depends
    36	#             -> add to NEW_DEPENDS
    37	#             -> libstate.add_depends
    38	#       -> optional_depends|suggest_depends <provider> (external)
    39	#         -> work_optional_depends_provider
    40	#           -> select provider
    41	#           -> private_common_depends
    42	#             -> add to NEW_DEPENDS
    43	#             -> libstate.add_depends
    44	#     -> private_add_depends
    45	#       -> update hash tables and lists from NEW_DEPENDS
    46	#
    47	# in other words, for every spell run its external files
    48	# and then deal with their callbacks (depends and optional_depends)
    49	# each of those calls eventually arrives at a dependency rule
    50	# which is stored somewhere through libstate calls , and in an internal
    51	# variable (NEW_DEPENDS). After we finish all the files we bundle up
    52	# our new information and move to the next spell.
    53	#
    54	
    55	# Surprise env vars:
    56	# SPELL: this is actually locally defined somewhere up the call stack
    57	#  but from most function's point of view it should be there...
    58	# COMPILE: set in cast. It means that the main">main">main">main">main spells should be recompiled
    59	# RECONFIGURE: set in cast. I means that the info in the state depends should
    60	#  be disregarded and replaced.
    61	# PRETEND_NOT_INSTALLED: set here. It is a list of spells that are to be
    62	#  recompiled, so they should not be treated as installed.
    63	# CAST_HASH: The name of the hast table to put spells and dependencies
    64	#  that are to be cast (only used in this lib)
    65	# BACK_HASH: reverse of CAST_HASH will be used to handle failures
    66	#  more gracefully someday...
    67	# CANNOT_CAST: The name of the hash table to put spells that cannot be cast
    68	#  and the reason why. Usualy because they are exiled or don't exist
    69	#  (only used in this lib)
    70	
    71	
    72	######################BEGIN CALLS TO OUTSIDE WORLD########################
    73	
    74	#---------------------------------------------------------------------
    75	## Run the spell's PREPARE script if it exists
    76	## @param Spell to prepare
    77	## @Globals SCRIPT_DIRECTORY
    78	#---------------------------------------------------------------------
    79	function run_prepare()
    80	{
    81	  local SPELL=$1
    82	
    83	  debug "cast" "run_prepare() - SPELL = $SPELL  SCRIPT_DIRECTORY = $SCRIPT_DIRECTORY"
    84	
    85	  depends_message  "${SPELL}" "preparing environment..."
    86	
    87	  # these are here so you can source section/grimoire level scripts in
    88	  # PREPARE, which by definition runs before the spell is loaded
    89	  # and they are defined as usual (see bug 8329)
    90	  codex_get_spell_paths "$SCRIPT_DIRECTORY"
    91	
    92	  local PROTECT_SORCERY=yes
    93	  run_spell_file PREPARE prepare
    94	  rc=$?
    95	  return $rc
    96	}
    97	
    98	#---------------------------------------------------------------------
    99	## This will be home to all "other" questions we are supposed to ask about
   100	## during this phase of things, right now its a placeholder
   101	## @param Spell
   102	#---------------------------------------------------------------------
   103	function run_other() {
   104	  local SPELL=$1
   105	  # ask the questions about xinetd/initd script installation
   106	  persistent_load &&
   107	  query_services &&
   108	  query_custom_cflags &&
   109	  query_conflicts &&
   110	  run_security &&
   111	  persistent_save ||
   112	  {
   113	    persistent_clear
   114	    log_failure_reason run_other #remove this if all the previous callers get one
   115	    return 1
   116	  }
   117	#ask about other stuff
   118	
   119	}
   120	
   121	#---------------------------------------------------------------------
   122	## Run the spell's CONFIGURE script if it exists
   123	## @param Spell to configure
   124	#---------------------------------------------------------------------
   125	function run_configure() {
   126	  local SPELL=$1
   127	  debug "cast" "run_configure() - SCRIPT_DIRECTORY = $SCRIPT_DIRECTORY"
   128	
   129	  function run_configure_msg() {
   130	    depends_message  "${SPELL}" "running configuration..."
   131	  }
   132	
   133	  local PROTECT_SORCERY=yes
   134	  run_spell_file CONFIGURE configure run_configure_msg
   135	  rc=$?
   136	  return $rc
   137	}
   138	
   139	#---------------------------------------------------------------------
   140	## Run a spell's DEPENDS if it exists
   141	## @param Spell
   142	#---------------------------------------------------------------------
   143	function run_depends() {
   144	  local SPELL=$1
   145	  debug "cast" "run_depends() - SCRIPT_DIRECTORY = $SCRIPT_DIRECTORY"
   146	
   147	  function run_depends_msg() {
   148	    depends_message  "${SPELL}" "checking dependencies..."
   149	  }
   150	
   151	  local PROTECT_SORCERY=yes
   152	  run_spell_file DEPENDS depends run_depends_msg
   153	  rc=$?
   154	  return $rc
   155	}
   156	
   157	#---------------------------------------------------------------------
   158	## Run a spell's UP_TRIGGERS if it exists
   159	## @param Spell
   160	#---------------------------------------------------------------------
   161	function run_up_triggers() {
   162	  local SPELL=$1
   163	  debug "cast" "run_up_triggers() - SCRIPT_DIRECTORY = $SCRIPT_DIRECTORY"
   164	
   165	  function run_up_triggers_msg() {
   166	    depends_message  "${SPELL}" "checking for reverse triggers..."
   167	  }
   168	  local PROTECT_SORCERY=yes
   169	  run_spell_file UP_TRIGGERS up_triggers run_up_triggers_msg
   170	  rc=$?
   171	  return $rc
   172	}
   173	
   174	#---------------------------------------------------------------------
   175	## process any sub-depends the current spell is going to provide
   176	## These come from the live sub-depends table and from spells that
   177	## have already been processed
   178	#---------------------------------------------------------------------
   179	function run_our_sub_depends() {
   180	  $STD_DEBUG
   181	  local sub_depends pair
   182	  # do all sub-depends on us from live-table first, they get priority
   183	  # in case there is a conflict
   184	  for triple in $(search_sub_depends "$SUB_DEPENDS_STATUS" '.*' "$SPELL") ; do
   185	    # parse the line out, eventually these silly variable expansions should
   186	    # be in functions or benchmarked against explode
   187	    tmp=${triple%:*};
   188	    requester=${tmp%:*};
   189	    sub_dependee=${tmp#*:};
   190	    sub_depends=${triple##*:}
   191	
   192	    # if the requester has been processed skip any sub-depends its
   193	    # previous instance requested, bug 11865
   194	    local hash_depends_looked_at
   195	    hash_get_ref "depends_looked_at" "$requester" hash_depends_looked_at
   196	    [[ $hash_depends_looked_at == done ]] && continue
   197	
   198	    process_sub_depends "$requester" "$sub_dependee" "$sub_depends" || return 1
   199	  done
   200	
   201	  # do all sub-depends from sub_dep_r_hash (things that we provide)
   202	  for pair in $(hash_get sub_dep_r_hash $SPELL) ; do
   203	    requester=${pair%:*}
   204	    sub_depends=${pair#*:}
   205	
   206	    process_sub_depends "$requester" "$SPELL" "$sub_depends" || return 1
   207	  done
   208	}
   209	
   210	#---------------------------------------------------------------------
   211	## run any sub-depends that we requested on behalf of the sub-dependee
   212	#---------------------------------------------------------------------
   213	function run_other_sub_depends() {
   214	  $STD_DEBUG
   215	  local this_spell=$1
   216	  local SPELL sub_dependee sub_depends pair
   217	  local sub_dependee_looked_at
   218	  # do all sub-depends from sub_dep_f_hash (things we request)
   219	  for pair in $(hash_get sub_dep_f_hash $this_spell) ; do
   220	    # FIXME, do this one spell at a time, rather than in whatever order we
   221	    # see them it will reduce the number of run_details
   222	    sub_dependee=${pair%:*}
   223	    sub_depends=${pair#*:}
   224	    hash_get_ref depends_looked_at $sub_dependee sub_dependee_looked_at
   225	    if [[ $sub_dependee_looked_at == done ]]; then
   226	      # load the spell and clear out any special variables
   227	      SPELL=$sub_dependee
   228	      run_details
   229	      local NEW_SUB_DEPENDEES=""
   230	      # afk 5-28-06: bash 3.0 breaks local foo=(), have to make this two lines
   231	      local NEW_DEPENDS; NEW_DEPENDS=()
   232	      local NEW_RUNTIME_DEPENDS; NEW_RUNTIME_DEPENDS=()
   233	      process_sub_depends "$this_spell" "$sub_dependee" "$sub_depends" ||
   234	      return 1
   235	
   236	      # this is needed in case processing the sub-depends added a depends
   237	      # isnt this fun?
   238	      private_add_depends
   239	    fi
   240	  done
   241	}
   242	
   243	#---------------------------------------------------------------------
   244	## Run a spell's SUB_DEPENDS file for a specific sub-depends.
   245	## This is idempotent, if a sub-depends has already been processed it will
   246	## not run the SUB_DEPENDS file again.
   247	##
   248	## Expects the sub-dependee to be loaded.
   249	## If the spell does not have a SUB_DEPENDS file, it is a failure.
   250	#---------------------------------------------------------------------
   251	function process_sub_depends() {
   252	  $STD_DEBUG
   253	  local requester=$1
   254	  local sub_dependee=$2
   255	  local sub_depends=$3
   256	  local PROTECT_SORCERY=yes
   257	
   258	  if test -x $SCRIPT_DIRECTORY/SUB_DEPENDS; then
   259	    if ! list_find "$(hash_get processed_sub_depends $sub_dependee)" "$sub_depends"; then
   260	      local rc=0
   261	
   262	      local THIS_SUB_DEPENDS=$sub_depends
   263	      local PROCESSED_SUB_DEPENDS
   264	      hash_get_ref processed_sub_depends $sub_dependee PROCESSED_SUB_DEPENDS
   265	      run_spell_file SUB_DEPENDS sub_depends || return 1
   266	      hash_append processed_sub_depends $sub_dependee $sub_depends
   267	    else
   268	      debug libdepends "SUB_DEPENDS: $sub_dependee needs to provide $sub_depends but has already been processed"
   269	    fi
   270	  else
   271	    # sub-depends file doesnt exist, something messed up somewhere
   272	    return 1
   273	  fi
   274	  # add the information to the uncommitted depends file
   275	  local sub_depends_file rsub_depends_file
   276	  get_uncommitted_sub_depends_file "$sub_dependee" sub_depends_file || return 1
   277	  add_sub_depends "$sub_depends_file" "$requester" "$sub_dependee" "$sub_depends"
   278	  get_uncommitted_rsub_depends_file "$requester" rsub_depends_file || return 1
   279	  add_sub_depends "$rsub_depends_file" "$requester" "$sub_dependee" "$sub_depends"
   280	}
   281	
   282	######################END CALLS TO OUTSIDE WORLD########################
   283	
   284	#---------------------------------------------------------------------
   285	## Create a map of spells to their dependent spells.
   286	## Then for all installed or held spells, output a libhash command to
   287	## join the spell name and dependency info.
   288	## Then evaluate the output, thus filling a libhash with dependency info.
   289	## @param Name of hash table to put dependencies
   290	#---------------------------------------------------------------------
   291	function compute_installed_depends() {
   292	  #$1==hash table to fill
   293	  local hash=$1
   294	  touch $DEPENDS_STATUS $SPELL_STATUS &>/dev/null
   295	
   296	  local pattern status
   297	  if [[ $2 ]] ; then
   298	    pattern="required|optional|runtime|suggest"
   299	  else
   300	    pattern="required|optional"
   301	  fi
   302	  status=${3:-on}
   303	
   304	  # From here forward $1 and $2 are only used to refer to awk variables
   305	
   306	  lock_file "$DEPENDS_STATUS"
   307	  lock_file "$SPELL_STATUS"
   308	  # sub(/(.*)/, "", $2) removes a provider name
   309	  eval $(awk -v pattern="$pattern" -v status="$status" -F : 'BEGIN {
   310	    while (getline < ARGV[1] ) {
   311	      if( $3==status && ( $4 ~ pattern ) ) {
   312	        sub(/\(.*\)/, "", $2);
   313	        depmap[$1]=depmap[$1]" "$2" "
   314	      }
   315	    }
   316	    while (getline < ARGV[2] ) {
   317	      if( $3=="installed" || $3=="held") {
   318	        printf("hash_put $hash %s \"%s\";\n",$1,depmap[$1]);
   319	      }
   320	    }
   321	  }' $DEPENDS_STATUS $SPELL_STATUS )
   322	  unlock_file "$DEPENDS_STATUS"
   323	  unlock_file "$SPELL_STATUS"
   324	}
   325	
   326	#---------------------------------------------------------------------
   327	## Create a map of spells to their dependent spells.
   328	## Then for all installed or held spells, output a libhash command to
   329	## join the spell name and dependency info.
   330	## Then evaluate the output, thus filling a libhash with dependency info.
   331	## @param Name of hash table to fill with dependencies
   332	#---------------------------------------------------------------------
   333	function compute_reverse_installed_depends() {
   334	  #$1==hash table to fill
   335	  local hash=$1
   336	  touch $DEPENDS_STATUS $SPELL_STATUS &>/dev/null
   337	
   338	  local pattern status
   339	  if [[ $2 ]] ; then
   340	    pattern="required|optional|runtime|suggest"
   341	  else
   342	    pattern="required|optional"
   343	  fi
   344	  status=${3:-on}
   345	
   346	  # From here forward $1 and $2 are only used to refer to awk variables
   347	
   348	  lock_file "$DEPENDS_STATUS"
   349	  lock_file "$SPELL_STATUS"
   350	  # sub(/(.*)/, "", $2) removes a provider name
   351	  eval $(awk -v pattern="$pattern" -v status="$status" -F : 'BEGIN {
   352	    while (getline < ARGV[1] ) {
   353	      if( $3==status && ( $4 ~ pattern ) ) {
   354	        sub(/\(.*\)/, "", $2);
   355	        depmap[$2]=depmap[$2]" "$1" "
   356	      }
   357	    }
   358	    while (getline < ARGV[2] ) {
   359	      if( $3=="installed" || $3=="held") {
   360	        printf("hash_put $hash %s \"%s\";\n",$1,depmap[$1]);
   361	      }
   362	    }
   363	  }' $DEPENDS_STATUS $SPELL_STATUS )
   364	  unlock_file "$DEPENDS_STATUS"
   365	  unlock_file "$SPELL_STATUS"
   366	}
   367	
   368	#---------------------------------------------------------------------
   369	## calling this will accomplish several things:
   370	## <ol>
   371	## <li> most importantly it finds the closure of all spells that need to
   372	##    be cast
   373	## <li> it builds a hash table mapping spells to their depends, possibly by
   374	##    asking the user for input
   375	## <li> it updates DEPENDS_STATUS, arguably it shouldn't be doing this.
   376	## </ol>
   377	##
   378	## What happens: take all the spells we've been asked to resolve
   379	## for each one of them run its details file
   380	## the details file will call back to depends/optional_depends
   381	## at this point we determine/find/query for depends info
   382	## update the hash table, update DEPENDS_STATUS, and append to the
   383	## list of spells to resolve
   384	##
   385	## @param Hashtable name for dependencies
   386	## @param Hashtable name for spells with problem in resolution (or something)
   387	## @param Hashtable name for spells which cannot cast
   388	#---------------------------------------------------------------------
   389	function compute_uninstalled_depends()
   390	{
   391	
   392	  # $1=table to place spells in
   393	  # $2=table to put problem spells in, $* = root spells
   394	
   395	  debug "libdepends" "compute_depends of $*"
   396	  local CAST_HASH="$1"
   397	  local BACK_CAST_HASH="$2"
   398	  local CANNOT_CAST_HASH="$3"
   399	  BONUS_SPELLS=()
   400	  shift 3
   401	  local spell spells
   402	  spells=( $@ )
   403	
   404	  PRETEND_NOT_INSTALLED=" $@ "
   405	
   406	  local _idx
   407	  local looked_at
   408	
   409	  # this is a list of all spells basesystem depends on it is used to
   410	  # avoid loops with the "everything depends on basesystem" feature
   411	  local base_deps
   412	  base_deps=$(search_depends_status $DEPENDS_STATUS basesystem|cut -f2 -d:)
   413	
   414	  # All specified spells are assumed to be not installed, or else -c and -r
   415	  # would have to be specified all the time.
   416	
   417	  for (( _idx=0 ; _idx<${#spells[*]} ; _idx++ )) ; do
   418	    hash_get_ref depends_looked_at ${spells[$_idx]} looked_at
   419	    if [[ ! $looked_at ]]; then
   420	      if ! private_run_depends ${spells[$_idx]} ; then
   421	        # i dont know if this will work, but it will have to suffice
   422	        private_remove_dependees ${spells[$_idx]}
   423	      fi
   424	    else
   425	      debug "libdepends" "already looked at ${spells[$_idx]}, skipping"
   426	    fi
   427	  done
   428	  # we no longer need these, no sense in keeping them around
   429	  hash_unset depends_looked_at
   430	  hash_unset sub_dep_f_hash
   431	  hash_unset sub_dep_r_hash
   432	  hash_unset sub_depends_process
   433	  hash_unset processed_sub_depends
   434	
   435	  # we need this so processes on the other side of make know whats going on
   436	  hash_export uncommitted_hash
   437	
   438	  BONUS_SPELLS=( ${BONUS_SPELLS[*]} ${UP_DEPENDS[*]} )
   439	}
   440	
   441	#---------------------------------------------------------------------
   442	## A private function for running a spell's DEPENDS script.
   443	## No functions except libdepends functions should use this.
   444	## @param Spell
   445	#---------------------------------------------------------------------
   446	function private_run_depends()
   447	{
   448	  debug "libdepends" "$FUNCNAME - $*"
   449	  local SPELL=$1
   450	
   451	  # special accumulators for the current spell
   452	  local NEW_DEPENDS=""
   453	  local NEW_SUB_DEPENDEES=""
   454	  local NEW_RUNTIME_DEPENDS=""
   455	  local NEW_UP_DEPENDS=""
   456	  local triggerees=""
   457	  local spell_depends
   458	  local spell_sub_depends
   459	
   460	  hash_put "depends_looked_at" "$SPELL" "start"
   461	
   462	  # We only need to run the stuff if we are going to be casting.
   463	  # It only needs to be added to the casting hash table if we are
   464	  # really casting it
   465	  if private_should_cast $SPELL ; then
   466	
   467	    # this cant go in private_should_cast because then the dependee wont
   468	    # have a chance at being fixed
   469	    # we check already here, so a specified spell isn't needlessly run
   470	    if spell_exiled $1; then
   471	      depends_message  "${SPELL}" "is exiled and will not be cast."
   472	      log_failure_reason exiled $1
   473	      return 1
   474	    fi
   475	    get_uncommitted_depends_file $SPELL spell_depends
   476	    spell_sub_depends=$spell_depends.sub
   477	    if  [  -n  "$RECONFIGURE"  ];  then
   478	      local t_abandonded_p
   479	      rm  -f  $DEPENDS_CONFIG/$SPELL
   480	      test -f $DEPENDS_CONFIG/$SPELL.p &&
   481	      mkdir -p $ABANDONED_PERSIST      &&
   482	      lock_file "$DEPENDS_CONFIG/$SPELL.p" &&
   483	      lock_start_transaction "$ABANDONED_PERSIST/$SPELL.p" t_abandonded_p &&
   484	      mv -f "$DEPENDS_CONFIG/$SPELL.p" "$t_abandonded_p" &&
   485	      unlock_file "$DEPENDS_CONFIG/$SPELL.p" &&
   486	      lock_commit_transaction "$ABANDONED_PERSIST/$SPELL.p"
   487	    fi
   488	    prepare_spell_config
   489	    SCRIPT_DIRECTORY=`codex_find_spell_by_name $SPELL`
   490	    run_prepare $SPELL            &&
   491	    run_details                   &&
   492	    run_configure $SPELL          &&
   493	    run_other $SPELL              &&
   494	    run_depends $SPELL            &&
   495	    run_up_triggers $SPELL        &&
   496	    run_our_sub_depends $SPELL        &&
   497	
   498	    # possibly recast things that depend on us if option is set (-B)
   499	    private_upward_depends $SPELL &&
   500	    private_recast_optionals $SPELL &&
   501	    private_add_triggerees        &&
   502	    private_add_depends           ||
   503	    { debug "libdepends" "$FUNCNAME failed to process $SPELL." ; return 1; }
   504	    # no point in keeping the file around if its empty...
   505	    test -s $spell_depends || rm -f $spell_depends $spell_sub_depends
   506	
   507	    if real_list_find "${RUNTIME_DEPENDS[*]}" "$SPELL"; then
   508	      local k=${#BONUS_SPELLS[@]}
   509	      BONUS_SPELLS[$k]=$SPELL
   510	    fi
   511	
   512	    # this processes any sub-depends we requested and the sub-dependee
   513	    # has already been processed, so we must process them on their behalf
   514	    # this must be done after everything else!
   515	    run_other_sub_depends "$SPELL" || return 1
   516	  else
   517	    depends_message "${SPELL}" "No work to do."
   518	    hash_put "depends_looked_at" "$SPELL" "ignore"
   519	  fi
   520	
   521	  # if there weren't any depends no sense in keeping the file around
   522	  return 0
   523	}
   524	
   525	#---------------------------------------------------------------------
   526	## Decides if a spell should be cast, or if we can leave it alone.
   527	## Check if the spell is installed, or if theres some other reason to
   528	## rebuild it.
   529	## @param Spell
   530	#---------------------------------------------------------------------
   531	function private_should_cast()
   532	{
   533	  local each
   534	  # order is important here...
   535	  if ! codex_does_spell_exist $1; then
   536	    return 1
   537	  elif real_list_find "$PRETEND_NOT_INSTALLED" $1 ; then
   538	    # always look at stuff on the command line unless its exiled
   539	    return 0
   540	  # from here on the spell was not on the command line...
   541	  elif spell_held $1;  then
   542	    # don't recast held even with -R
   543	    return 1
   544	  elif [[ "$RECAST_DOWN" ]] ; then
   545	    # user gave -R so recast...
   546	    return 0
   547	  elif real_list_find "${UP_DEPENDS[*]}" $1; then
   548	    # if someone has determined this is an upward depend (-B)
   549	    return 0
   550	  elif real_list_find "${TRIGGEREES[*]}" $1; then
   551	    # if its being triggered we need to look at it, despite its
   552	    # installed status
   553	    return 0
   554	  elif real_list_find "${FORCE_DEPENDS[*]}" $1; then
   555	    return 0
   556	  elif [[ "$(hash_get sub_depends_process $1)" != "" ]] ; then
   557	    return 0
   558	  elif spell_installed $1 ; then
   559	    # returns success if want to cast
   560	    want_lazy_update $1 && return 0 || return 1
   561	  fi
   562	
   563	  # we must need to install this as we know nothing else about it
   564	  return 0
   565	}
   566	#---------------------------------------------------------------------
   567	## @param Spell name
   568	## Find all the spells that depend on the spell given as $1
   569	#---------------------------------------------------------------------
   570	function private_upward_depends() {
   571	  if [[ "$RECAST_UP" ]] ; then
   572	    local tmp
   573	    # Note, use the reverse depends tree for this when we get a chance
   574	    # and/or move the weird pattern into library functions...
   575	    # (afrayedknot 2005-10-02)
   576	    lock_file "$DEPENDS_STATUS"
   577	    tmp=$(grep "^.*:$1\(([^:]*)\)\?:" $DEPENDS_STATUS|cut -f1 -d:|tr "\n" " ")
   578	    unlock_file "$DEPENDS_STATUS"
   579	    local j k each
   580	    let j=${#NEW_UP_DEPENDS[*]}
   581	    for each in $tmp; do
   582	      NEW_UP_DEPENDS[$j]=$each
   583	      let j++
   584	    done
   585	    spells=( ${spells[*]} ${tmp} )
   586	  fi
   587	}
   588	
   589	# shared code for both loops in private_recast_optionals
   590	private_recast_optionals_sub() {
   591	  local spell="$1"
   592	  local message="$2"
   593	
   594	  enabled=""
   595	  message "$message"
   596	  if [[ $RECAST_OPTIONALS == always ]]; then
   597	    enabled=yes
   598	  else
   599	    local default=n
   600	    [[ $RECAST_OPTIONALS == ask-yes ]] && default=y
   601	    if query "Recast $spell with the dependency enabled?" $default; then
   602	      enabled=yes
   603	    fi
   604	  fi
   605	}
   606	
   607	#---------------------------------------------------------------------
   608	## Find spells that optionally depended on the current spell but had the
   609	## dependency disabled, ask if the user wants to recast the spell.
   610	## Also finds disabled features that the current spell is a provider of.
   611	#---------------------------------------------------------------------
   612	function private_recast_optionals() {
   613	  if [[ $RECAST_OPTIONALS ]] && [[ $RECAST_OPTIONALS != ignore ]] ; then
   614	    local spell j enabled
   615	    let j=${#NEW_UP_DEPENDS[*]}
   616	    for spell in $(search_depends_status_exact $DEPENDS_STATUS \
   617	                 '.*' "$1\(([^:]*)\)\?" off optional '.*' '.*'|cut -f1 -d:); do
   618	      private_recast_optionals_sub $spell \
   619	        "$spell has a disabled optional dependency on $1"
   620	      if [[ $enabled ]] ; then
   621	        NEW_UP_DEPENDS[$j]=$spell
   622	        let j++
   623	        # toggle the dependency, so the user doesn't get requeried
   624	        toggle_depends_status $DEPENDS_STATUS $spell "$1(\([^:]*\))?"
   625	        spells=( ${spells[*]} $spell )
   626	      fi
   627	    done
   628	
   629	    # also check for disabled features that $1 is a provider of
   630	    local features feature_regex
   631	    # get the features and build a regex for quicker lookup
   632	    features=$(codex_find_spell_provides $1)
   633	    for feature in $features; do
   634	      feature_regex="$feature\|$feature_regex"
   635	    done
   636	    feature_regex=${feature_regex%\\|}
   637	    for spell in $(search_depends_status_exact $DEPENDS_STATUS \
   638	                '.*' "($feature_regex)" off optional '.*' '.*'|cut -f1 -d:|sort -u); do
   639	      private_recast_optionals_sub $spell \
   640	        "$spell has a disabled optional dependency on $1 as a provider"
   641	      if [[ $enabled ]] ; then
   642	        NEW_UP_DEPENDS[$j]=$spell
   643	        let j++
   644	        # toggle all the features that $1 provides and set $1 as their provider
   645	        for feature in $features; do
   646	          change_spell_provider $DEPENDS_STATUS $spell "$1" "$feature" "on"
   647	        done
   648	        spells=( ${spells[*]} $spell )
   649	      fi
   650	    done
   651	  fi
   652	}
   653	
   654	###################BEGIN CALLBACKS FROM OUTSIDE#######################
   655	
   656	#---------------------------------------------------------------------
   657	## @param  spell or provider name
   658	## @param  addition to OPTS
   659	## @param  description
   660	## @param  grimoires to look in
   661	## Delegates provider and spell cases to different worker functions.
   662	## and gets grimoires if necessary for cross grimoire depends
   663	##
   664	## Called by real_depends and real_runtime_depends
   665	#---------------------------------------------------------------------
   666	function real_generic_required_depends()
   667	{
   668	  local failure_ok=$1
   669	  local article=$2
   670	  local query_term=$3
   671	  local database_term=$4
   672	  shift 4
   673	
   674	  if [[ "$1" == "-sub" ]] ; then
   675	    local requested_sub_depends=$2
   676	    shift 2
   677	  fi
   678	
   679	  if [[ $1 != ${1/ /} ]] ; then
   680	    message "${PROBLEM_COLOR}Spell names must not contain spaces:" \
   681	            "${DEFAULT_COLOR}${SPELL_COLOR}$1${DEFAULT_COLOR}"
   682	    return 1
   683	  fi
   684	
   685	  # determine if we're dealing with a provider or a spell
   686	  local is_provider
   687	  if ! codex_does_spell_exist $1 &> /dev/null; then
   688	    is_provider=yes
   689	  fi
   690	
   691	  # see if theres another grimoire
   692	  if [[ "$4" ]] && ! [[ "$OVERRIDE_GRIMOIRES" ]] ; then
   693	    local grimoire here nothere current
   694	
   695	    for grimoire in $4; do
   696	      if [[ "$grimoire" == "current" ]] ; then
   697	        current=yes
   698	      elif codex_find_grimoire "$grimoire" > /dev/null; then
   699	        list_add here $grimoire
   700	      else
   701	        list_add nothere $grimoire
   702	      fi
   703	    done
   704	    if [[ "$here" ]] || [[ "$current" ]] ; then
   705	      if [[ "$nothere" ]] ; then
   706	        depends_message "$SPELL" "has $article $query_term on${is_provider+ some}" "$1" "from $4."
   707	        message "${SPELL_COLOR}$1${DEFAULT_COLOR}${CHECK_COLOR}" \
   708	                "exists in the following grimoires${DEFAULT_COLOR}" \
   709	                "${SPELL_COLOR}${4}${DEFAULT_COLOR}${CHECK_COLOR}"
   710	        message "You dont have ${SPELL_COLOR}$nothere${DEFAULT_COLOR}" \
   711	                "${CHECK_COLOR}but you have ${SPELL_COLOR}$here${DEFAULT_COLOR}"
   712	        for grimoire in $nothere ; do
   713	          if query "Get $grimoire grimoire?" n; then
   714	            scribe add "$grimoire"
   715	            unset GRIMOIRE_DIR[*]
   716	            source $GRIMOIRE_LIST
   717	            if codex_find_grimoire "$grimoire" > /dev/null; then
   718	              list_add here $grimoire
   719	            else
   720	              message "${PROBLEM_COLOR}Failed to get grimoire${DEFAULT_COLOR}"
   721	            fi
   722	          fi
   723	        done
   724	    # else
   725	    #   have all the grimoires, nothing to do, this is probably the case most
   726	    #   of the time
   727	      fi
   728	    else
   729	      if [[ "$nothere" ]] ; then
   730	        depends_message "$SPELL" "has $article $query_term on${is_provider+ some}" "$1" "from $4."
   731	        message "${CHECK_COLOR}You dont have any of the grimoires" \
   732	                "${SPELL_COLOR}$4${DEFAULT_COLOR}${CHECK_COLOR}."
   733	        message "You must add at least one grimoire to satisfy the" \
   734	                "dependency.${DEFAULT_COLOR}"
   735	        for grimoire in $nothere ; do
   736	          if query "Get $grimoire grimoire?" n; then
   737	            scribe add "$grimoire"
   738	            unset GRIMOIRE_DIR[*]
   739	            source $GRIMOIRE_LIST
   740	            if codex_find_grimoire "$grimoire" > /dev/null; then
   741	              list_add here $grimoire
   742	            else
   743	              message "${PROBLEM_COLOR}Failed to get grimoire${DEFAULT_COLOR}"
   744	            fi
   745	          fi
   746	        done
   747	      else
   748	        # this is a bug, most likely with list_add in order for this
   749	        # to happen, there has to be some grimoires to look in, and the
   750	        # grimoires are neither installed nor uninstalled
   751	        message "This is a bug, probably with list_add, please contact the" \
   752	                "sorcery team, thanks."
   753	        return 1
   754	      fi
   755	    fi
   756	    if [[ ! $here ]] && [[ ! $current ]] ; then
   757	      message "${PROBLEM_COLOR}no grimoire for $1 was retrieved${DEFAULT_COLOR}"
   758	      if [[ $failure_ok == "no" ]] || ! query "Build $1 anyway?" y; then
   759	        return 1
   760	      fi
   761	    fi
   762	  fi
   763	
   764	  local target_spell
   765	  if [[ $is_provider ]]; then
   766	    work_depends_provider "$failure_ok" "$article" \
   767	                                   "$query_term" "$database_term" "$@" &&
   768	    if [[ "$requested_sub_depends" ]]; then
   769	      target_spell=$(get_spell_provider "$SPELL" "$1")
   770	    fi
   771	  else
   772	    work_depends_spell "$failure_ok" "$article" \
   773	                                   "$query_term" "$database_term" "$@" &&
   774	    target_spell=$1
   775	  fi &&
   776	  for sub_depend in $requested_sub_depends; do
   777	    sub_depends "$target_spell" "$sub_depend" || return 1
   778	  done
   779	}
   780	
   781	
   782	#---------------------------------------------------------------------
   783	## Passthrough to real_generic_required_depends, specifies the
   784	## parts that differ from runtime depends
   785	#---------------------------------------------------------------------
   786	function real_depends() {
   787	  real_generic_required_depends "no" "a" "dependency" "required" "$@"
   788	}
   789	
   790	#---------------------------------------------------------------------
   791	## Passthrough to real_generic_required_depends, specifies the
   792	## parts that differ from required depends
   793	#---------------------------------------------------------------------
   794	function real_runtime_depends() {
   795	  real_generic_required_depends "yes" "a" "runtime dependency" "runtime" "$@"
   796	}
   797	
   798	
   799	#---------------------------------------------------------------------
   800	## @param  spell or provider name
   801	## @param  addition to OPTS if enabled
   802	## @param  addition to OPTS if disabled
   803	## @param  description
   804	## @param  grimoires to look in
   805	## Delegates provider and spell cases to different worker functions.
   806	##
   807	## Called by real_depends and real_runtime_depends
   808	#---------------------------------------------------------------------
   809	function real_generic_optional_depends()
   810	{
   811	  local failure_ok=$1
   812	  local article=$2
   813	  local query_term=$3
   814	  local database_term=$4
   815	  shift 4
   816	
   817	  if [[ "$1" == "-sub" ]] ; then
   818	    local requested_sub_depends=$2
   819	    shift 2
   820	  fi
   821	
   822	  if [[ $1 != ${1/ /} ]] ; then
   823	    message "${PROBLEM_COLOR}Spell names must not contain spaces:" \
   824	            "${DEFAULT_COLOR}${SPELL_COLOR}$1${DEFAULT_COLOR}"
   825	    return 1
   826	  fi
   827	
   828	  # determine if we're dealing with a provider or a spell
   829	  local is_provider
   830	  if ! codex_does_spell_exist $1 &> /dev/null; then
   831	    is_provider=yes
   832	  fi
   833	
   834	  # see if theres another grimoire
   835	  if [[ "$5" ]] && ! [[ "$OVERRIDE_GRIMOIRES" ]] ; then
   836	    local grimoire here nothere current
   837	    for grimoire in $5; do
   838	      if [[ "$grimoire" == "current" ]] ; then
   839	        current=yes
   840	      elif codex_find_grimoire "$grimoire" > /dev/null; then
   841	        list_add here $grimoire
   842	      else
   843	        list_add nothere $grimoire
   844	      fi
   845	    done
   846	    if [[ "$here" ]] || [[ "$current" ]] ; then
   847	      if [[ "$nothere" ]] ; then
   848	        depends_message "$SPELL" "has $article $query_term on${is_provider+ some}" "$1" "from $5."
   849	        message "${SPELL_COLOR}$1${DEFAULT_COLOR}${CHECK_COLOR}" \
   850	                "exists in the following grimoires${DEFAULT_COLOR}" \
   851	                "${SPELL_COLOR}${5}${DEFAULT_COLOR}${CHECK_COLOR}"
   852	        message "You dont have ${SPELL_COLOR}$nothere${DEFAULT_COLOR}" \
   853	                "${CHECK_COLOR}but you have ${SPELL_COLOR}$here${DEFAULT_COLOR}"
   854	        for grimoire in $nothere ; do
   855	          if query "Get $grimoire grimoire?" n; then
   856	            scribe add "$grimoire"
   857	            unset GRIMOIRE_DIR[*]
   858	            source $GRIMOIRE_LIST
   859	            if codex_find_grimoire "$grimoire" > /dev/null; then
   860	              list_add here $grimoire
   861	            else
   862	              message "${PROBLEM_COLOR}Failed to get grimoire${DEFAULT_COLOR}"
   863	            fi
   864	          fi
   865	        done
   866	    # else
   867	    #   have all the grimoires, nothing to do, this is probably the case most
   868	    #   of the time
   869	      fi
   870	    else
   871	      if [[ "$nothere" ]] ; then
   872	        depends_message "$SPELL" "has $article $query_term on${is_provider+ some}" "$1" "from $5."
   873	        message "${CHECK_COLOR}You dont have any of the grimoires" \
   874	                "${SPELL_COLOR}${5}${DEFAULT_COLOR}${CHECK_COLOR}."
   875	        for grimoire in $nothere ; do
   876	          if query "Get $grimoire grimoire?" n; then
   877	            scribe add "$grimoire"
   878	            unset GRIMOIRE_DIR[*]
   879	            source $GRIMOIRE_LIST
   880	            if codex_find_grimoire "$grimoire" > /dev/null; then
   881	              list_add here $grimoire
   882	            else
   883	              message "${PROBLEM_COLOR}Failed to get grimoire${DEFAULT_COLOR}"
   884	            fi
   885	          fi
   886	        done
   887	      else
   888	        # this is a bug, most likely with list_add in order for this
   889	        # to happen, there has to be some grimoires to look in, and the
   890	        # grimoires are neither installed nor uninstalled
   891	        message "This is a bug, probably with list_add, please contact the" \
   892	                "sorcery team, thanks."
   893	        return 1
   894	      fi
   895	    fi
   896	    if [[ ! $here ]] && [[ ! $current ]] ; then
   897	      message "${PROBLEM_COLOR}no grimoire for $1 was retrieved${DEFAULT_COLOR}"
   898	      message "Assuming dependency is off because it could not be met"
   899	      if [[ $is_provider ]]; then
   900	        private_common_depends "($1)" "off" "$database_term" "$2" "$3"
   901	      else
   902	        private_common_depends "$1" "off" "$database_term" "$2" "$3"
   903	      fi
   904	      return 0
   905	    fi
   906	  fi
   907	
   908	  local target_spell
   909	  if [[ $is_provider ]]; then
   910	    work_optional_depends_provider "$failure_ok" "$article" \
   911	                                   "$query_term" "$database_term" "$@" &&
   912	    if [[ "$requested_sub_depends" ]]; then
   913	      target_spell=$(get_spell_provider "$SPELL" "$1")
   914	    fi
   915	  else
   916	    work_optional_depends_spell "$failure_ok" "$article" \
   917	                                   "$query_term" "$database_term" "$@" &&
   918	    target_spell=$1
   919	  fi &&
   920	  if [[ "$requested_sub_depends" ]] &&
   921	     [[ "$target_spell" ]] &&
   922	     is_depends_enabled "$SPELL" "$target_spell"; then
   923	    for sub_depend in $requested_sub_depends; do
   924	      sub_depends "$target_spell" "$sub_depend" || return 1
   925	    done
   926	  fi
   927	
   928	}
   929	
   930	#---------------------------------------------------------------------
   931	## Passthrough to real_generic_optional_depends, specifies the
   932	## parts that differ from suggest depends
   933	#---------------------------------------------------------------------
   934	function real_optional_depends() {
   935	  real_generic_optional_depends "no" "an" "optional dependency" "optional" "$@"
   936	}
   937	
   938	#---------------------------------------------------------------------
   939	## Passthrough to real_generic_required_depends, specifies the
   940	## parts that differ from optional depends
   941	#---------------------------------------------------------------------
   942	function real_suggest_depends() {
   943	  real_generic_optional_depends "yes" "a" "suggested dependency" "suggest" "$@"
   944	}
   945	
   946	
   947	#---------------------------------------------------------------------
   948	## Asks the user what provider for a depends is desired if a choice
   949	## has not ben made before.
   950	## @param Service
   951	## @param Enabled options
   952	## @param Description
   953	#---------------------------------------------------------------------
   954	function work_depends_provider()
   955	{
   956	
   957	  debug "libdepends" "$FUNCNAME - $@"
   958	  local default tmp installed=no
   959	  local choices
   960	  local status=()
   961	
   962	  local failure_ok=$1
   963	  local article=$2
   964	  local query_term=$3
   965	  local database_term=$4
   966	  shift 4
   967	
   968	  if [[ $3 ]] ; then
   969	    depends_message "${SPELL}" "has $article $query_term on some" "${1}" "($3)."
   970	  else
   971	    depends_message "$SPELL" "has $article $query_term on some" "${1}."
   972	  fi
   973	
   974	  local CANDIDATES=$( find_providers $1)
   975	  if [[ ! $CANDIDATES ]] ; then
   976	    message "${PROBLEM_COLOR}No providers of${DEFAULT_COLOR}" \
   977	            "${SPELL_COLOR}$1${DEFAULT_COLOR}" \
   978	            "${PROBLEM_COLOR} can be found!${DEFAULT_COLOR}"
   979	    if [[ $failure_ok == "no" ]] || ! query "Build $1 anyway?" y; then
   980	      return 1
   981	    fi
   982	  fi
   983	
   984	  # if not reconfiguring check if theres already an answer in DEPENDS_STATUS
   985	  if [[ ! $RECONFIGURE ]]; then
   986	    # notice the clever ignorance of optional/required depends for the
   987	    # provider case, if the user chose none, we would fall out during spell_ok
   988	    # and we transparently switch between optional and required without
   989	    # anyone noticing
   990	    explode "$(search_depends_status $DEPENDS_STATUS "$SPELL" ".*($1)")" ":" "status"
   991	    tmp=${status[1]%(*}    # Name of spell which provides $1
   992	    if spell_ok $tmp; then
   993	      message "${MESSAGE_COLOR}Using ${SPELL_COLOR}$tmp${DEFAULT_COLOR}"
   994	      private_common_depends "$tmp($1)" "on" "$database_term" "$2" "$3"
   995	      return 0
   996	    fi
   997	  fi
   998	
   999	  # check if theres an abandoned answer, but only if its still a provider
  1000	  if [[ ! $default ]] && [ -e $ABANDONED_DEPENDS/$SPELL ] ; then
  1001	    tmp=$(search_depends_status $ABANDONED_DEPENDS/$SPELL "$SPELL" ".*($1)"|awk -F: '{print $2;exit}')
  1002	    [[ $tmp ]] && real_list_find "$CANDIDATES" "$tmp" && default=$tmp
  1003	  fi
  1004	
  1005	  # check if theres a default provider
  1006	  if [[ ! $default ]]; then
  1007	    explode "$(search_default_provider $DEFAULT_PROVIDERS ".*" "$1")" ":" "status"
  1008	    tmp=${status[0]}
  1009	    [[ $tmp ]] && real_list_find "$CANDIDATES" "$tmp" && default=$tmp
  1010	  fi
  1011	
  1012	  # check if we've already answered this question
  1013	  if [[ ! $default ]]; then
  1014	    for tmp in $CANDIDATES; do
  1015	      real_list_find "${spells[*]}" "$tmp" && default=$tmp && break
  1016	    done
  1017	  fi
  1018	
  1019	  # check if theres a provider already installed
  1020	  # if there are multiple, try to select the previously used one
  1021	  if [[ ! $default ]]; then
  1022	    for tmp in $CANDIDATES; do
  1023	      spell_ok $tmp && real_list_add choices $tmp
  1024	    done
  1025	    if [[ $choices == ${choices##* } ]]; then
  1026	      default=$choices
  1027	    else
  1028	      explode "$(search_depends_status $DEPENDS_STATUS "$SPELL" ".*($1)")" ":" "status"
  1029	      local old_provider=${status[1]%(*} # Name of spell which provides $1
  1030	      if real_list_find "$choices" $old_provider; then
  1031	        default=$old_provider
  1032	      else
  1033	        default=${choices%% *}
  1034	      fi
  1035	    fi
  1036	  fi
  1037	
  1038	  local provider
  1039	  select_provider "provider" "$default" 0 $CANDIDATES
  1040	
  1041	  private_common_depends "$provider($1)" "on" "$database_term" "$2" ""
  1042	}
  1043	
  1044	#---------------------------------------------------------------------
  1045	## One of the worker functions. Checks for exiled spell and passes
  1046	## on to the common dependency function, <@function private_common_depends>
  1047	## @param Spell
  1048	## @param enabled options
  1049	#---------------------------------------------------------------------
  1050	function work_depends_spell()
  1051	{
  1052	  debug "libdepends" "$FUNCNAME - $@"
  1053	
  1054	  local failure_ok=$1
  1055	  local article=$2
  1056	  local query_term=$3
  1057	  local database_term=$4
  1058	  shift 4
  1059	
  1060	  depends_message "${SPELL}" "has $article $query_term on" "$1"
  1061	
  1062	  if spell_exiled $1 ; then
  1063	    depends_message "${1}" "has been exiled!"
  1064	    if [[ $failure_ok == "no" ]] || ! query "Build $1 anyway?" y; then
  1065	      hash_put $CANNOT_CAST_HASH "$1" "Exiled"
  1066	      grep -qs $1 $FAILED_LIST || echo $1 >> $FAILED_LIST
  1067	      log_failure_reason exiled $1
  1068	      return 1
  1069	    fi
  1070	  fi
  1071	  private_common_depends "$1" "on" "$database_term" "$2" ""
  1072	
  1073	}
  1074	
  1075	#---------------------------------------------------------------------
  1076	## @param  provider name
  1077	## @param  addition to OPTS if enabled
  1078	## @param  addition to OPTS if disabled
  1079	## @param  description
  1080	## Handles optional dependency on a provider.
  1081	#---------------------------------------------------------------------
  1082	function work_optional_depends_provider()
  1083	{
  1084	
  1085	  debug "libdepends" "$FUNCNAME - $@"
  1086	  local default tmp choices installed=no
  1087	  local status=()
  1088	
  1089	  local failure_ok=$1
  1090	  local article=$2
  1091	  local query_term=$3
  1092	  local database_term=$4
  1093	  shift 4
  1094	
  1095	  if [[ $4 ]] ; then
  1096	    depends_message "${SPELL}" "has $article $query_term on some" "${1}" "($4)."
  1097	  else
  1098	    depends_message "${SPELL}" "has $article $query_term on some" "${1}."
  1099	  fi
  1100	
  1101	  local CANDIDATES=$( find_providers $1)
  1102	  # if not reconfiguring check if theres already an answer in DEPENDS_STATUS
  1103	  if [[ ! $RECONFIGURE ]]; then
  1104	    explode "$(search_depends_status_simple $DEPENDS_STATUS "$SPELL" ".*($1)" "on")" ":" "status"
  1105	    local tmp=${status[1]%(*}    # Name of spell which provides $1
  1106	    if [[ "$tmp" ]] && spell_ok "$tmp"; then
  1107	      message "${MESSAGE_COLOR}Using ${SPELL_COLOR}$tmp${DEFAULT_COLOR}"
  1108	      private_common_depends "$tmp($1)" "on" "$database_term" "$2" "$3"
  1109	      return 0
  1110	    fi
  1111	    if [[ "$(search_depends_status_simple $DEPENDS_STATUS \
  1112	                                          "$SPELL" ".*($1)" "off")" ]]; then
  1113	      message "${MESSAGE_COLOR}Using ${SPELL_COLOR}[none]${DEFAULT_COLOR}"
  1114	      private_common_depends "$tmp($1)" "off" "$database_term" "$2" "$3"
  1115	      return 0
  1116	    fi
  1117	  fi
  1118	
  1119	  # check if theres an abandoned answer, but only if its still a provider
  1120	  if [[ ! $default ]] && [ -e $ABANDONED_DEPENDS/$SPELL ] ; then
  1121	    tmp=$(search_depends_status_simple $ABANDONED_DEPENDS/$SPELL "$SPELL" ".*($1)" "on"|awk -F: '{print $2;exit}')
  1122	    if [[ $tmp ]] && real_list_find "$CANDIDATES" "$tmp"; then
  1123	      default=$tmp
  1124	    else
  1125	      tmp=$(search_depends_status_simple $ABANDONED_DEPENDS/$SPELL "$SPELL" ".*($1)" "off")
  1126	      [[ $tmp ]] && default=none
  1127	    fi
  1128	  fi
  1129	
  1130	  # check if theres a default provider
  1131	  if [[ ! $default ]]; then
  1132	    tmp=$(search_default_provider $DEFAULT_PROVIDERS ".*" "$1")
  1133	
  1134	    # make sure we found /something/ before trying to analyze it
  1135	    # otherwise we'll fall into the else case and use 'none' as the
  1136	    # provider, and short-circuit the other guesses
  1137	    if [[ $tmp ]] ; then
  1138	      explode "$tmp" ":" "status"
  1139	      tmp=${status[0]}
  1140	      if [[ ${status[2]} == on ]] ; then
  1141	        # if the user said "on" use the default rather than none
  1142	        # unless theres something wrong with the provider they chose
  1143	        # in which case fall back to none
  1144	        if [[ $tmp ]] && real_list_find "$CANDIDATES" "$tmp"; then
  1145	          default=$tmp
  1146	        else
  1147	          message "${PROBLEM_COLOR}The default provider is not good anymore!"
  1148	          message "Falling back to 'none' as the default choice.$DEFAULT_COLOR"
  1149	          default=none
  1150	        fi
  1151	      else
  1152	        default=none
  1153	      fi
  1154	    fi
  1155	  fi
  1156	
  1157	  # check if we've already answered this question
  1158	  if [[ ! $default ]]; then
  1159	    for tmp in $CANDIDATES; do
  1160	      real_list_find "${spells[*]}" "$tmp" && default=$tmp && break
  1161	    done
  1162	  fi
  1163	
  1164	  # check if theres a provider already installed
  1165	  # if there are multiple, try to select the previously used one
  1166	  if [[ ! $default ]]; then
  1167	    for tmp in $CANDIDATES; do
  1168	      spell_ok $tmp && real_list_add choices $tmp
  1169	    done
  1170	    if [[ $choices == ${choices##* } ]]; then
  1171	      default=$choices
  1172	    else
  1173	      # only search for enabled dependencies since none is already the default
  1174	      explode "$(search_depends_status_simple $DEPENDS_STATUS "$SPELL" ".*($1)" "on")" ":" "status"
  1175	      local old_provider=${status[1]%(*} # Name of spell which provides $1
  1176	      if real_list_find "$choices" $old_provider; then
  1177	        default=$old_provider
  1178	      else
  1179	        default=${choices%% *}
  1180	      fi
  1181	    fi
  1182	  fi
  1183	
  1184	  local provider
  1185	  select_provider "provider" "$default" 1 $CANDIDATES
  1186	
  1187	  if [ $provider == "none" ] ; then
  1188	    private_common_depends "($1)" "off" "$database_term" "$2" "$3"
  1189	  else
  1190	    private_common_depends "$provider($1)" "on" "$database_term" "$2" "$3"
  1191	  fi
  1192	
  1193	}
  1194	
  1195	#---------------------------------------------------------------------
  1196	## @param spell
  1197	## @param question
  1198	## @param default answer
  1199	##
  1200	## @return 0 on yes
  1201	## @return 1 on no
  1202	##
  1203	## Works just like normal query but can show short description of a
  1204	## spell and stops the timer for taking the default answer if
  1205	## h/H is pressed. Type of query is chosen in sorcery feature menu.
  1206	##
  1207	#---------------------------------------------------------------------
  1208	function optional_depends_query()  {
  1209	  local _response
  1210	  local spell_name=$1
  1211	  local time_to_answer=$PROMPT_DELAY
  1212	
  1213	  while true; do
  1214	    _response=""
  1215	
  1216	    if [[ -z $SILENT ]]; then
  1217	      if [[ $SHOW_GAZE_SHORT_QUERY == off ]]; then
  1218	        echo -e -n "${QUERY_COLOR}$2 [$3] ${DEFAULT_COLOR}"
  1219	      else
  1220	        if [[ $3 == y ]]; then
  1221	          echo -e -n "${QUERY_COLOR}$2 [Y/n/h] ${DEFAULT_COLOR}"
  1222	        else
  1223	          echo -e -n "${QUERY_COLOR}$2 [y/N/h] ${DEFAULT_COLOR}"
  1224	        fi
  1225	      fi
  1226	
  1227	      if [[ -n $time_to_answer ]]; then
  1228	        read -t $time_to_answer -n 1 _response
  1229	        echo
  1230	      else
  1231	        read -n 1 _response
  1232	        echo
  1233	      fi
  1234	    fi
  1235	
  1236	    _response=${_response:=$3}
  1237	    case  $_response in
  1238	      n|N) return 1 ;;
  1239	      y|Y) return 0 ;;
  1240	      h|H) ( codex_set_current_spell_by_name $spell_name
  1241	           echo $SHORT
  1242	           echo More information at: $WEB_SITE
  1243	           )
  1244	           unset time_to_answer
  1245	    esac
  1246	  done
  1247	}
  1248	
  1249	#---------------------------------------------------------------------
  1250	## @param  spell name
  1251	## @param  addition to OPTS if enabled
  1252	## @param  addition to OPTS if disabled
  1253	## @param  description
  1254	## Handles optional dependency on a spell.
  1255	#---------------------------------------------------------------------
  1256	function work_optional_depends_spell()
  1257	{
  1258	
  1259	  debug "libdepends" "$FUNCNAME - $@"
  1260	  local default
  1261	
  1262	  local failure_ok=$1
  1263	  local article=$2
  1264	  local query_term=$3
  1265	  local database_term=$4
  1266	  shift 4
  1267	
  1268	  # if $1 optionally depends on something exiled we always say no
  1269	  if spell_exiled $1 ; then
  1270	    depends_message "${1}" "has been exiled! not using as $article $query_term"
  1271	    # don't put it into the bad_spells hash, since it wasn't specified directly
  1272	    #hash_put $CANNOT_CAST_HASH "$1" "Exiled"
  1273	    private_common_depends "$1" "off" "$database_term" "$2" "$3"
  1274	    return 0
  1275	  fi
  1276	
  1277	
  1278	  if [[ ! $RECONFIGURE ]] ; then
  1279	    # See if there are preferences already in DEPENDS_STATUS, but only if
  1280	    # not reconfiguring...
  1281	    # example: icewm:imlib:off:optional:--with-imlib:--with-xpm
  1282	    local status=()
  1283	    explode "$(search_depends_status $DEPENDS_STATUS "$SPELL" "$1")" ":" "status"
  1284	    if [[ ${status[2]} ]] ; then
  1285	      # ah there are! use them
  1286	      if [[ ${status[2]} == "on" ]] ; then
  1287	        depends_message "${SPELL}" "has an enabled $query_term on" "${1}"
  1288	      else
  1289	        depends_message "${SPELL}" "has a disabled $query_term on" "${1}"
  1290	      fi
  1291	      private_common_depends "$1" "${status[2]}" "$database_term" "$2" "$3"
  1292	      return 0
  1293	    fi
  1294	  fi
  1295	  # colors differ from depends_message
  1296	  if [[ $4 ]]; then
  1297	    message "${SPELL_COLOR}${SPELL}${DEFAULT_COLOR}" \
  1298	            "has $article $query_term on" \
  1299	            "${SPELL_COLOR}$1${DEFAULT_COLOR} ($4)"
  1300	  else
  1301	    message "${SPELL_COLOR}${SPELL}${DEFAULT_COLOR}" \
  1302	            "has $article $query_term on" \
  1303	            "${SPELL_COLOR}$1${DEFAULT_COLOR}"
  1304	  fi
  1305	
  1306	
  1307	  # check for abandoned answers
  1308	  if [ -e $ABANDONED_DEPENDS/$SPELL ] ; then
  1309	    debug "libdepends" "Checking in abandoned depends"
  1310	    default=$(search_depends_status $ABANDONED_DEPENDS/$SPELL "$SPELL" "$1"|awk -F: '{print $3;exit}')
  1311	  fi
  1312	
  1313	  # check the defaults file...
  1314	  # first for explicit $SPELL -> $2
  1315	  if [[ ! $default ]]; then
  1316	    debug "libdepends" "Checking in default answers"
  1317	    default=$(search_default_depends $DEFAULT_DEPENDS $SPELL $1|awk -F: '{print $3; exit}')
  1318	  fi
  1319	
  1320	  # then for anything -> $2
  1321	  if [[ ! $default ]]; then
  1322	    debug "libdepends" "Checking in default answers"
  1323	    default=$(search_default_depends $DEFAULT_DEPENDS "" $1|awk -F: '{print $3; exit}')
  1324	  fi
  1325	
  1326	  # then for $1 -> anything
  1327	  if [[ ! $default ]]; then
  1328	    debug "libdepends" "Checking in default answers"
  1329	    default=$(search_default_depends $DEFAULT_DEPENDS $SPELL "" |awk -F: '{print $3; exit}')
  1330	  fi
  1331	
  1332	  # check the install queue
  1333	  if [[ ! $default ]]; then
  1334	    debug "libdepends" "Checking in queue"
  1335	    real_list_find "${spells[*]}" "$1" && default=on
  1336	  fi
  1337	
  1338	  # check if installed/held
  1339	  if [[ ! $default ]]; then
  1340	    debug "libdepends" "Checking if already installed"
  1341	    spell_ok $1 && default=on
  1342	  fi
  1343	
  1344	  # otherwise default to no
  1345	  [[ ! $default ]] && default=off
  1346	
  1347	  local install=off
  1348	
  1349	  local stuff
  1350	  [[ $default == off ]] && stuff=n || stuff=y
  1351	
  1352	  if spell_ok $1 ; then
  1353	    optional_depends_query "$1" "Do you want to use ${SPELL_COLOR}$1${QUERY_COLOR}?" "$stuff" &&
  1354	        install="on"
  1355	  else
  1356	    optional_depends_query "$1" "Do you want to cast ${SPELL_COLOR}$1${QUERY_COLOR}?" "$stuff" &&
  1357	        install="on"
  1358	  fi
  1359	
  1360	  private_common_depends "$1" "$install" "$database_term" "$2" "$3"
  1361	}
  1362	
  1363	#---------------------------------------------------------------------
  1364	## @param  name of return variable
  1365	## @param  default answer
  1366	## @param  0 if required 1 if optional
  1367	## @param  list of possible providers
  1368	## Present a list to the user complete with info about whats installed
  1369	## and what isnt and allow a default value to be used
  1370	#---------------------------------------------------------------------
  1371	function select_provider()
  1372	{
  1373	    local returnvar=$1
  1374	    local default=$2
  1375	    local optional=$3
  1376	    local i
  1377	    shift 3
  1378	
  1379	    local each default_char=0 stuff=()
  1380	    local char
  1381	
  1382	    # we can only read one character so use every one we can, I dont expect
  1383	    # there to be more than 62 providers
  1384	
  1385	    # in bash 3.0 this expands to all the numbers and letters
  1386	    # stuff=({0..9} {a..z} {A..Z})
  1387	    # but we're still on bash 2 which cant do that, if someone
  1388	    # knows a better way to do this please tell me
  1389	    stuff=(0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
  1390	
  1391	    if [ $optional == 1 ] ; then
  1392	      hash_put CHAR_TO_SPELL 0 "none"
  1393	      let i=1
  1394	      message "\t${DEFAULT_COLOR}(0)\t${SPELL_COLOR}[none]${DEFAULT_COLOR}"
  1395	    else
  1396	      let i=0
  1397	    fi
  1398	
  1399	    for each in $@; do
  1400	      char=${stuff[$i]}
  1401	      hash_put CHAR_TO_SPELL $char $each
  1402	
  1403	      [[ $each == $default ]] && default_char=$char
  1404	      if spell_ok $each ; then
  1405	        message "\t${DEFAULT_COLOR}($char)\t${SPELL_COLOR}$each${DEFAULT_COLOR}\t (installed)"
  1406	      else
  1407	        message "\t${DEFAULT_COLOR}($char)\t${SPELL_COLOR}$each${DEFAULT_COLOR}"
  1408	      fi
  1409	      let i++
  1410	    done
  1411	
  1412	    local msg="\n${QUERY_COLOR}Which one do you want? [$default_char]$DEFAULT_COLOR "
  1413	    select_list_sub "$returnvar" CHAR_TO_SPELL "$msg" "$default_char"
  1414	    hash_unset CHAR_TO_SPELL
  1415	}
  1416	
  1417	#---------------------------------------------------------------------
  1418	## @param Target of the trigger
  1419	## @param Action to execute (cast_self, check_self, etc).
  1420	##
  1421	## Create a trigger on ourself effecting the target spell,
  1422	## shorthand for putting a TRIGGERS file in the target spell.
  1423	#---------------------------------------------------------------------
  1424	function real_up_trigger() {
  1425	  message  "${SPELL_COLOR}${SPELL}${DEFAULT_COLOR}" \
  1426	           "${CHECK_COLOR}triggers a${DEFAULT_COLOR}" \
  1427	           "${SPELL_COLOR}${2}${DEFAULT_COLOR}" \
  1428	           "${CHECK_COLOR}on${DEFAULT_COLOR}" \
  1429	           "${SPELL_COLOR}${1}${DEFAULT_COLOR}"
  1430	  private_up_trigger $SPELL "$1" "$2"
  1431	}
  1432	
  1433	#---------------------------------------------------------------------
  1434	## @param Current spell
  1435	## @param Target target of the trigger
  1436	## @param Action to execute (cast_self, check_self, etc).
  1437	##
  1438	## Register a trigger, when $SPELL is cast, a $ACTION is executed
  1439	## on $TARGET
  1440	#---------------------------------------------------------------------
  1441	function private_up_trigger() {
  1442	  local SPELL=$1
  1443	  local TARGET=$2
  1444	  local ACTION=$3
  1445	  # this maps triggerers to their trigerees
  1446	  # perl -> cast_self:perl_module
  1447	  hash_append trg_f_hash  $SPELL "$TARGET:$ACTION" $'\n' &&
  1448	  # this maps trigerees to triggerers
  1449	  # cast_self:perl_module -> perl
  1450	  hash_append trg_r_hash  "$TARGET:$ACTION" " $SPELL "
  1451	
  1452	  # afk 6-7-06 Im not sure this line is correct, it seems to only
  1453	  # make a circular depends, instead we want $TARGET to depend on $SPELL
  1454	  real_list_find "${NEW_DEPENDS[*]}" "$TARGET" ||
  1455	  NEW_DEPENDS=( ${NEW_DEPENDS[*]} $spell)
  1456	
  1457	  triggerees=( ${triggerees[*]} $TARGET )
  1458	}
  1459	
  1460	#---------------------------------------------------------------------
  1461	## @param spell providing the sub-depends
  1462	## @param name of sub-depends
  1463	##
  1464	## Request a sub-depends from $SPELL on $1 for $2
  1465	## This queues the sub-depends for later processing, if the sub-dependee
  1466	## does not already support the sub-depends.
  1467	#---------------------------------------------------------------------
  1468	function real_sub_depends() {
  1469	  $STD_DEBUG
  1470	  local requester=$SPELL
  1471	  local sub_dependee=$1
  1472	  local sub_depends=$2
  1473	
  1474	  message "${SPELL_COLOR}${SPELL}${MESSAGE_COLOR} requests" \
  1475	          "${SPELL_COLOR}$sub_dependee${DEFAULT_COLOR}" \
  1476	          "${CHECK_COLOR}with ${SPELL_COLOR}$sub_depends${DEFAULT_COLOR}"
  1477	
  1478	  # Check if the sub-depends is already known
  1479	  if spell_ok $sub_dependee; then
  1480	    if [[ $(search_sub_depends "$SUB_DEPENDS_STATUS" "$requester" \
  1481	                              "$sub_dependee" "$sub_depends") != "" ]]; then
  1482	      debug "libdepends" "$FUNCNAME -- $requester -> $sub_dependee" \
  1483	                         "-> $sub_depends provided by installed spell"
  1484	      return 0
  1485	    fi
  1486	
  1487	    # the spell is installed, but the sub-depends isn't recorded, ask the
  1488	    # spell if the sub-depends is enabled through the PRE_SUB_DEPENDS file.
  1489	    (
  1490	      THIS_SUB_DEPENDS=$sub_depends
  1491	      if ! tablet_set_spell $sub_dependee ; then
  1492	        codex_set_current_spell_by_name $sub_dependee || return 1
  1493	      fi
  1494	      run_spell_file PRE_SUB_DEPENDS pre_sub_depends
  1495	      rc=$?
  1496	      return $rc
  1497	    ) && {
  1498	      debug "libdepends" "adding altruistic sub-depends for $sub_dependee with $sub_depends from $requester"
  1499	      add_sub_depends "$SUB_DEPENDS_STATUS" "$requester" \
  1500	                      "$sub_dependee" "$sub_depends"
  1501	      hash_append sub_dep_f_hash $requester $sub_dependee:$sub_depends $'\n'
  1502	      hash_append sub_dep_r_hash $sub_dependee $requester:$sub_depends $'\n'
  1503	      return 0
  1504	    }
  1505	  fi
  1506	
  1507	  # if didnt return above, then we know the sub-depends is not on the system
  1508	  # so the spell must be (re)cast, check to see if we're allowed to do that
  1509	  if ! real_list_find "$PRETEND_NOT_INSTALLED" $sub_dependee &&
  1510	     spell_held $sub_dependee; then
  1511	    # spell is held and not explicitly requested, so we cant recast the
  1512	    # spell with the sub-depends requested
  1513	    message "${PROBLEM_COLOR}Sub-depends requested on" \
  1514	            "a held spell: $SPELL_COLOR$sub_dependee$DEFAULT_COLOR"
  1515	    return 1
  1516	  fi
  1517	
  1518	  # add to hashes for lookup later in depends resolution
  1519	  hash_append sub_dep_f_hash $requester $sub_dependee:$sub_depends $'\n'
  1520	  hash_append sub_dep_r_hash $sub_dependee $requester:$sub_depends $'\n'
  1521	
  1522	  # spell is either not installed, or is installed but without the
  1523	  # sub-depends, we must (re)cast it
  1524	  NEW_SUB_DEPENDEES=( ${NEW_SUB_DEPENDEES[*]} $sub_dependee )
  1525	  hash_put sub_depends_process $sub_dependee "yes"
  1526	  return 0
  1527	}
  1528	
  1529	#---------------------------------------------------------------------
  1530	## Force a spell to be recast, if it comes up for processing
  1531	## if the spell was already looked at and processed nothing happens
  1532	## if the spell was already looked at and didnt need processing, then
  1533	## it'll get re-processed (assuming the caller also did a depends on it)
  1534	#---------------------------------------------------------------------
  1535	function real_force_depends() {
  1536	  debug "libdepends" "$FUNCNAME - $SPELL - $@"
  1537	  local check
  1538	  hash_get_ref "depends_looked_at" "$1" check
  1539	
  1540	  message "${SPELL}" "is forcing a recast of" "${1}"
  1541	
  1542	  if [[ "$check" == "ignore" ]] ; then
  1543	    hash_put "depends_looked_at" "$1" ""
  1544	  fi
  1545	  FORCE_DEPENDS=( ${FORCE_DEPENDS[*]} $1 )
  1546	}
  1547	
  1548	#---------------------------------------------------------------------
  1549	## all the depends callbacks eventually bottom out here
  1550	## if a spell depends or doesnt depend on some other spell
  1551	## @param Spell
  1552	## @param on/off
  1553	#---------------------------------------------------------------------
  1554	function private_common_depends()
  1555	{
  1556	  debug "libdepends" "$FUNCNAME - $SPELL - $@"
  1557	  add_depends $spell_depends "$SPELL" "$@"
  1558	
  1559	  # runtime and suggested depends have no formal dependency info
  1560	  if [[ $2 == on ]] ; then
  1561	    # ${1%(*} = spell name (strips potential provider name)
  1562	    local spell_name=${1%(*}
  1563	    case $3 in
  1564	      runtime|suggest)
  1565	           NEW_RUNTIME_DEPENDS=( ${NEW_RUNTIME_DEPENDS[*]} $spell_name ) ;;
  1566	      *)   NEW_DEPENDS=( ${NEW_DEPENDS[*]} $spell_name ) ;;
  1567	    esac
  1568	  fi
  1569	
  1570	
  1571	  return 0
  1572	}
  1573	
  1574	#---------------------------------------------------------------------
  1575	## Default trigger checking function. Asks user if they want to
  1576	## run the trigger.
  1577	#---------------------------------------------------------------------
  1578	function real_default_sorcery_trigger_check() {
  1579	  message  "${SPELL_COLOR}${SPELL}${DEFAULT_COLOR}" \
  1580	           "${CHECK_COLOR}triggers a" \
  1581	           "${SPELL_COLOR}${ACTION}${DEFAULT_COLOR}" \
  1582	           "${CHECK_COLOR}on${DEFAULT_COLOR}" \
  1583	           "${SPELL_COLOR}${TARGET}${DEFAULT_COLOR}"
  1584	  query "Run the trigger?" y
  1585	}
  1586	
  1587	#---------------------------------------------------------------------
  1588	## Inspects each trigger, asks the user if they want to run it.
  1589	#---------------------------------------------------------------------
  1590	function private_add_triggerees() {
  1591	
  1592	  # add the spells that we trigger to the $spells list
  1593	  # having duplicate items is okay
  1594	  local ACTION TARGET
  1595	  local running_trigger
  1596	
  1597	  # run the trigger check file
  1598	  # this is made into a sub-function just to reduce duplication...
  1599	  function private_add_triggerees_sub1() {
  1600	    run_spell_file TRIGGER_CHECK trigger_check
  1601	    running_trigger=$?
  1602	    if [[ $running_trigger == 0 ]] ; then
  1603	      private_up_trigger "$SPELL" "$TARGET" "$ACTION"
  1604	    fi
  1605	  }
  1606	
  1607	  # frontend to help">help">help with calling the trigger check file
  1608	  function private_add_triggerees_sub2() {
  1609	    local ACTION=$1
  1610	    private_add_triggerees_sub1
  1611	  }
  1612	
  1613	  for ACTION in cast_self check_self dispel_self run_script; do
  1614	    for TARGET in $(get_triggerees $SPELL on_cast $ACTION); do
  1615	      spell_ok $TARGET || continue
  1616	      if [[ $ACTION == run_script ]] ; then
  1617	        iterate private_add_triggerees_sub2 $'\n' \
  1618	                          "$(get_run_script_triggers $SPELL on_cast $TARGET)"
  1619	      else
  1620	        private_add_triggerees_sub1
  1621	      fi
  1622	    done
  1623	  done
  1624	  return 0
  1625	}
  1626	
  1627	
  1628	#---------------------------------------------------------------------
  1629	## Adds the dependency to the hastable
  1630	#---------------------------------------------------------------------
  1631	function private_add_depends()
  1632	{
  1633	  debug "libdepends" "$FUNCNAME: SPELL=$SPELL, NEW_DEPENDS=${NEW_DEPENDS[*]}"
  1634	  hash_append "$CAST_HASH" "$SPELL" "${NEW_DEPENDS[*]}"
  1635	
  1636	  for child in ${NEW_DEPENDS[*]}; do
  1637	    hash_append "$BACK_CAST_HASH" "$child" "$SPELL"
  1638	  done
  1639	
  1640	  # force implied basesystem dependency in the depends tree
  1641	  if [[ $FORCE_BASESYSTEM_DEPENDS == on ]] &&
  1642	     [[ $SPELL != basesystem ]] &&
  1643	     ! real_list_find "$base_deps" "$SPELL"; then
  1644	    hash_append "$CAST_HASH" "$SPELL" "basesystem"
  1645	    hash_append "$BACK_CAST_HASH" "basesystem" "$SPELL"
  1646	  fi
  1647	
  1648	  spells=( ${spells[*]} ${NEW_DEPENDS[*]}
  1649	                        ${NEW_SUB_DEPENDEES[*]}
  1650	                        ${NEW_RUNTIME_DEPENDS[*]} )
  1651	
  1652	  RUNTIME_DEPENDS=( ${RUNTIME_DEPENDS[*]} ${NEW_RUNTIME_DEPENDS[*]} )
  1653	
  1654	  TRIGGEREES=( ${TRIGGEREES[*]} ${triggerees[*]} )
  1655	  spells=( ${spells[*]} ${triggerees[*]} )
  1656	
  1657	  UP_DEPENDS=( ${UP_DEPENDS[*]} ${NEW_UP_DEPENDS[*]} )
  1658	
  1659	  hash_put "depends_looked_at" "$SPELL" "done"
  1660	
  1661	}
  1662	
  1663	#---------------------------------------------------------------------
  1664	## Determine if spell should be lazily updated, possible asks the user
  1665	## what to do.
  1666	#---------------------------------------------------------------------
  1667	function want_lazy_update() {
  1668	  if [[ $LAZY_DEPENDS_UPDATES ]] && [[ $LAZY_DEPENDS_UPDATES != ignore ]] ; then
  1669	    if does_spell_need_update "$1" ; then
  1670	      depends_message "$1" "needs updating"
  1671	      if [[ "$LAZY_DEPENDS_UPDATES" == always ]] ; then
  1672	        return 0
  1673	      else
  1674	        default=n
  1675	        [[ $LAZY_DEPENDS_UPDATES == ask-yes ]] && default=y
  1676	        query "Would you like to update it?" $default && return 0 || return 1
  1677	      fi
  1678	    fi
  1679	  fi
  1680	  return 1
  1681	}
  1682	
  1683	function depends_message() {
  1684	  if [[ $# -ge 2 ]] ; then
  1685	    message -n "${SPELL_COLOR}${1}${DEFAULT_COLOR}" \
  1686	               "${CHECK_COLOR}${2}${DEFAULT_COLOR}"
  1687	  fi
  1688	  if [[ $# -ge 3 ]] ; then
  1689	    message -n " ${SPELL_COLOR}${3}${DEFAULT_COLOR}"
  1690	  fi
  1691	  if [[ $# -ge 4 ]] ; then
  1692	    message -n " $4"
  1693	  fi
  1694	  message ""
  1695	}
  1696	
  1697	#########################BEGIN OTHER STUFF############################
  1698	
  1699	#---------------------------------------------------------------------
  1700	## @param Spell name
  1701	## Removes a dependency and its dependees from the to_cast list.
  1702	#---------------------------------------------------------------------
  1703	function private_remove_dependees()
  1704	{
  1705	  local spell=$1
  1706	  local removed_list dependee dependees
  1707	  message "${PROBLEM_COLOR}Removing dependees of $SPELL_COLOR$spell$DEFAULT_COLOR"
  1708	
  1709	  # take care of the spell
  1710	  private_discard_spell $spell fail
  1711	
  1712	  # take care of the dependees and their dependees and ...
  1713	  recurse_remove_dependees() {
  1714	    local spell=$1
  1715	    local dependees dependee
  1716	    while uncommitted_upward_depends $spell dependees; do
  1717	      [[ -z $dependees ]] && break
  1718	      for dependee in $dependees; do
  1719	        private_discard_spell $dependee
  1720	        real_list_add removed_list $dependee
  1721	        recurse_remove_dependees $dependee
  1722	      done
  1723	    done
  1724	  }
  1725	
  1726	  recurse_remove_dependees $spell
  1727	
  1728	  # take care of dependencies of removed dependees
  1729	  # but don't remove them if they were specified manually or
  1730	  # if they wouldn't be cast at all or
  1731	  # if something else needs them
  1732	  recurse_remove_dependencies() {
  1733	    local spell=$1
  1734	    local dependency dependees ignore dependees2
  1735	    # use BACK_CAST_HASH since we've already cleared CAST_HASH
  1736	    # it is in the form of dependency : dependee1 dependee2 ...
  1737	    for dependency in $(hash_get_table_fields $BACK_CAST_HASH); do
  1738	      hash_get_ref $BACK_CAST_HASH $dependency dependees
  1739	      if real_list_find "$dependees" $spell &&
  1740	        hash_get_ref "depends_looked_at" "$dependency" ignore &&
  1741	        [[ $ignore != ignore ]] &&
  1742	        uncommitted_upward_depends $dependency dependees2 &&
  1743	        [[ -z $dependees2 ]] &&
  1744	        ! real_list_find "$SPELLS" $dependency; then
  1745	          hash_unset_part $BACK_CAST_HASH $dependency $spell
  1746	          private_discard_spell $dependency
  1747	          recurse_remove_dependencies $dependency
  1748	      fi
  1749	    done
  1750	  }
  1751	
  1752	  for dependee in $removed_list; do
  1753	    recurse_remove_dependencies $dependee
  1754	  done
  1755	}
  1756	
  1757	#---------------------------------------------------------------------
  1758	## @param Spell name
  1759	## Does the actual removal
  1760	#---------------------------------------------------------------------
  1761	function private_discard_spell()
  1762	{
  1763	  local spell=$1
  1764	  local failed=$2
  1765	
  1766	  grep -qs $spell $FAILED_LIST && return 0
  1767	
  1768	  if [[ $failed == fail ]]; then
  1769	    # spell is being removed from cast list, add to FAILED_LIST
  1770	    # the rest we want to just show up as dropped
  1771	    echo "$spell" >> $FAILED_LIST
  1772	  fi
  1773	  hash_put depends_looked_at $spell failed
  1774	  hash_unset "$CAST_HASH" "$spell"
  1775	  hash_put $CANNOT_CAST_HASH "$spell" "Failed"
  1776	
  1777	  local bonus=${BONUS_SPELLS[@]}
  1778	  local up_depends=${UP_DEPENDS[@]}
  1779	  if real_list_find "$bonus" $spell; then
  1780	    real_list_remove bonus $spell
  1781	    BONUS_SPELLS=( $bonus )
  1782	  fi
  1783	  if real_list_find "$up_depends" $spell; then
  1784	    real_list_remove up_depends $spell
  1785	    UP_DEPENDS=( $up_depends )
  1786	  fi
  1787	}
  1788	
  1789	#---------------------------------------------------------------------
  1790	## @param Spell name
  1791	## @param Return variable
  1792	## Find all the spells already processed that depend on the spell given as $1
  1793	## Unlike private_upward_depends, this one works with the uncommitted info
  1794	#---------------------------------------------------------------------
  1795	function uncommitted_upward_depends() {
  1796	  local _spell=$1
  1797	  local _upvar=$2
  1798	  local candidate _dependees _deps
  1799	
  1800	  for candidate in $(hash_get_table_fields $CAST_HASH); do
  1801	    hash_get_ref $CAST_HASH $candidate _deps
  1802	    if real_list_find "$_deps" $_spell; then
  1803	      real_list_add _dependees $candidate
  1804	    fi
  1805	  done
  1806	
  1807	  if [[ -n $_upvar ]]; then
  1808	    upvar $_upvar $_dependees
  1809	  else
  1810	    echo $_dependees
  1811	  fi
  1812	}
  1813	
  1814	#---------------------------------------------------------------------
  1815	## Sets a spell's aux. config info.
  1816	## @Globals SPELL
  1817	#---------------------------------------------------------------------
  1818	function run_spell_config()
  1819	{
  1820	
  1821	  SPELL_CONFIG=$DEPENDS_CONFIG/$SPELL
  1822	  debug "libdepends" "run_spell_config() - DEPENDS_CONFIG=$DEPENDS_CONFIG SPELL=$SPELL, SPELL_CONFIG=$SPELL_CONFIG DEPENDS_STATUS=$DEPENDS_STATUS"
  1823	
  1824	  if  [  -x  $SPELL_CONFIG  ];  then
  1825	    debug "libdepends" "run_spell_config() - found $SPELL_CONFIG"
  1826	    .  $SPELL_CONFIG
  1827	  fi
  1828	}
  1829	
  1830	#---------------------------------------------------------------------
  1831	## Output the upward dependencies of the specified spell
  1832	## @Param spell
  1833	## @Param depth (optional)
  1834	## @Param fast -- if set only show spells, not full depends db entries
  1835	## @Param all - if set returns also runtime dependencies
  1836	#---------------------------------------------------------------------
  1837	function real_show_up_depends()
  1838	{
  1839	    local i=0
  1840	    local MAX_DEPTH=$2
  1841	    local type=$3
  1842	    local all=$4
  1843	    function show_up_depends_sub() {
  1844	        local each dependencies checked
  1845	        let i++
  1846	        [[ $MAX_DEPTH ]] && [[ $i -gt $MAX_DEPTH ]] && return
  1847	        hash_get_ref foo $1 dependencies
  1848	        for each in $dependencies; do
  1849	            hash_get_ref done $each checked
  1850	            if ! [[ $checked ]] ; then
  1851	                hash_put done $each done
  1852	                echo $each:$1
  1853	                show_up_depends_sub $each
  1854	            elif [[ "$type" == "verbose" ]] ; then
  1855	                echo $each:$1
  1856	            fi
  1857	        done
  1858	    }
  1859	    hash_reset foo
  1860	    hash_reset done
  1861	    compute_reverse_installed_depends foo $all
  1862	    if [[ "$type" == "verbose" ]] ; then
  1863	      lock_file "$DEPENDS_STATUS"
  1864	      show_up_depends_sub "$1"|while read line; do
  1865	        grep -e "$line:" -e "$line([^)(]*):" "$DEPENDS_STATUS"
  1866	      done
  1867	      unlock_file "$DEPENDS_STATUS"
  1868	    else
  1869	      show_up_depends_sub "$1"|cut -f1 -d:
  1870	    fi|sort -u
  1871	    hash_reset foo
  1872	    hash_reset done
  1873	}
  1874	
  1875	
  1876	#---------------------------------------------------------------------
  1877	##=back
  1878	##
  1879	##=head1 LICENSE
  1880	##
  1881	## This software is free software; you can redistribute it and/or modify
  1882	## it under the terms of the GNU General Public License as published by
  1883	## the Free Software Foundation; either version 2 of the License, or
  1884	## (at your option) any later version.
  1885	##
  1886	## This software is distributed in the hope that it will be useful,
  1887	## but WITHOUT ANY WARRANTY; without even the implied warranty of
  1888	## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1889	## GNU General Public License for more details.
  1890	##
  1891	## You should have received a copy of the GNU General Public License
  1892	## along with this software; if not, write to the Free Software
  1893	## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  1894	##
  1895	#---------------------------------------------------------------------