/* Compute the transitive closure of namespaces to search for each scope
   that we traverse. We keep looking outwards till we reach global scope
   (had there been a local i we wouldn't have been looking at using 
   directives).

   (i) Get the namespace name from the using directive.
   (ii) Check list of aliases - and find the true name of the
        namespace if this is an alias e.g if B is C::D add C::D to the list.
   (iii) Add true name to list of namespaces if not already present.
   (iv) For every namespace that you have added check the usings inside
        that namespace and add the true names of those namespaces too
        to the list.
   (v) If we are in a function in a namespace (add all prefixes of this
       namespace to the list of namespaces to be searched) e.g if you are
       in A::B::foo add A::B and A to the list.(Check aliases as you add)
   
 */
/* local is a NULL pointer when we call find_using_directives from 
   decode_line_1_reuse since we do not want it to exit if it
   finds a local but instead to complete building a list of the
   using directives - Do not change where it seems like it is 
   checking for local for no good reason.*/

static struct symbol *
find_using_directives (name, block, namespace, is_a_field_of_this, 
		       symtab, local, sym)
     const char **name;
     const struct block *block;
     const namespace_enum namespace;
     int *is_a_field_of_this;
     struct symtab **symtab;
     int *local;
     struct symbol *sym;
{
  extern struct block* expression_context_block;
  struct block* context_block; /* JAGaf45626 */
  char *actual_name;
  const char *real_name = (char *) *name;
  const struct block *block1 = block;
  const struct block *bl = NULL;
  int sym_alloc = INIT_SYM_ALLOC;
  int i = 0, rit_len = 0, j = 0, k = 0;
  char *ptr = NULL, *name_no_paren = NULL, *paren_ptr = NULL, 
    *doub_colon = NULL;
  
  num_ns_symbols = 0;
  num_symbol_names = 0;
  num_new_names = 0;
  symbol_names = NULL;
  using_syms = NULL;
  ns_symbols = NULL;  
  using_alloc = INIT_USING_ALLOC;
  names_alloc = INIT_USING_ALLOC;

  /* If you have a mangled name - don't do the namespace stuff below since
     you know exactly what you are looking for.*/
  if (   is_cplus_name ((const char *) *name) 
      && current_language->la_language == language_cplus)
    return sym;

  symbol_names = (char **) xmalloc (using_alloc * sizeof (char *));
  using_syms = (struct symbol **) xmalloc (using_alloc * 
					  sizeof (struct symbol *));
  ns_symbols = (struct symbol **) xmalloc (sym_alloc * 
					  sizeof (struct symbol *));
  new_names =  (char **) xmalloc (names_alloc * sizeof (char *));

  if (sym)
    ns_symbols[num_ns_symbols++] = sym;

  /* Looking for using directives and hence constructing additional
     symbols to look for only makes sense if you are stopped in
     a file somewhere and hence have a current block to start with.
     since using directives are valid only for that file. 
     So make sure you have a block - if not then return the symbol
     that the regular lookup found.
     */
  /* JAGaf45626 - Update expressions's context block only when the 
     current context is not null. Otherwise, gdb will lose the 
     expression context block and hence, fail to parse the rest of 
     the expression */ 

  context_block = get_selected_block ();
  if (context_block)
    expression_context_block = context_block;

  bl = block ? block : context_block;
  if (!bl)
    return sym;
  
  /* The first thing to do is to see if the current symbol is
     actually an alias for another.
     e.g if the user says print foo::a where foo is an
     alias for namespace A::B. The actual name of the symbol
     is A::B::a and so do a regular lookup for A::B::a. If you find 
     that it is a local (due to a using declaration) then call 
     choose_symbol to return.
     */

  actual_name = (char *) check_alias (*name, bl, NULL);
  if (local && strcmp (real_name, actual_name))
    {
      sym = lookup_symbol_1 (actual_name, bl, namespace, NULL, NULL, local);
      if (sym)
	{
	  ns_symbols[num_ns_symbols++] = sym;
	  if (*local)
	    return choose_symbol(*name, sym);
	}
    }
  
  /* If you didn't find the symbol in the block passed in from outside
     then look in the current block that you are stopped in.
   */

  if (local && !sym && block)
    {
      sym = lookup_symbol_1 (actual_name, context_block, namespace, 
			     NULL, NULL, local);
      if (sym)
	{
	  ns_symbols[num_ns_symbols++] = sym;
	  if (*local)
	    return choose_symbol(*name, sym);
	}
    }
  
  /* If we are in a function in a namespace (add all prefixes of this
     namespace to the list of namespaces to be searched) e.g if you are
     in A::B::foo add A::B and A to the list.
     The string may also look like A::B::foo<> - ignore the template
     braces.
     */
  
  block1 = block ? block : context_block;
  if (block1 && BLOCK_FUNCTION(block1))
    {
      char *func_name = BLOCK_FUNCTION(block1)->ginfo.name;
      char *block_name = func_name;
      /* If this is mangled demangle it first without the argument list*/
      if (is_cplus_name (func_name))
	block_name = cplus_demangle (func_name, DMGL_ANSI);

      if (block_name)
	{
	  char *ns_name, *end_ptr, *fore_ptr;
	  ns_name = (char *) alloca (strlen (block_name) + 1);
	  fore_ptr = strdup (block_name);
	  end_ptr = fore_ptr + strlen (fore_ptr) - 1;
	  while (end_ptr > fore_ptr)
	    {
	      if (*end_ptr == '>')
		{
		  end_ptr = go_to_matching (fore_ptr, '<', '>', end_ptr);
		  fore_ptr[end_ptr - fore_ptr] = '\0';
		}
	      end_ptr = strrstr (fore_ptr, "::");
	      if (end_ptr)
		{
		  strncpy (ns_name, fore_ptr, end_ptr - fore_ptr);
		  ns_name[end_ptr-fore_ptr] = '\0';
		  fore_ptr[end_ptr - fore_ptr] = '\0';
		  end_ptr--;
		  symbol_names[num_symbol_names++] = strdup(ns_name);
		}
	    }
	  free (fore_ptr);
	}
    }
  
  /* If there is a namespace selected by the user try that 
     out first and only if you don't find one do the stuff below. To 
     be implemented after the select command where a user can select
     a namespace to look in.*/

  /* If a user has said print A::D::a look in the namespace A::D for
     its using directives.
     namespace A { 
         namespace D {using namespace B;};
	 };
     namespace B { using namespace C;}
     namespace C { using namespace A::D;}
     ...
     We will look in namespace A::D, we find B and add B::a to our list. 
     Then we will look in B and add C::a to our list and so on.
     Transitive closure is mantained hence A::a does not get added again.
     We do not need to look in namespace A since it is enough to consider 
     only the longest prefix.
     */

  add_new_names (actual_name, bl);
  
  /* Walk the current block outwards to find all the using directives. 
     e.g 
     namespace A {...};
     namespace B {...};
     using namespace A;
     int main()
     { using namespace B; }

     If we are stopped in main we will add B and A to the list of
     namespaces. Each using directive is a block. The block structure 
     has been modified to hold a namespace symbol - if we find 
     that we know the block is a using directive. 
   */
    
  while (bl != 0)
    {
      struct symbol *func;
      func = BLOCK_NAMESPACE(bl);
      if (func && func->type && func->type->code == TYPE_CODE_USINGDIR)
	{
	  struct symbol *new_sym;
	  int i = 0, j = 0;
	  if (num_symbol_names)
	    {
	      for (i = 0; i < num_symbol_names; ++i)
		if (!strcmp (symbol_names[i], func->ginfo.name))
		  break;
	    }
	  
	  if (i == num_symbol_names) 
	    /* The name of this using isn't on the list */
	    {
	      if (num_symbol_names == using_alloc)
		{
		  symbol_names = (char **) xrealloc (symbol_names, 
						   2 * using_alloc *
						   sizeof (char *));
		  using_alloc *= 2;
		}
	      symbol_names[num_symbol_names++] = strdup(func->ginfo.name);
	    }
	}
      bl = BLOCK_SUPERBLOCK(bl);
    }
  
  /* For each namespace that we have found (after we looked for using
     directives) - look inside these namespaces for additonal using
     directives */

  for (i = 0; i < num_symbol_names; ++i)
    {
      /* Caution: num_symbol_names changes in the loop 
	 For each namespace in here - lookup the namespace
	 and add all it's using's with transitive
	 closure to the list e.g 
	 list currently has [A, B]
	 A has using ns B, using ns D
	 List after looking at A has [A, B, D]
	 B has using ns C
	 List after looking at B has [A, B, D, C]
	 C has using ns A
	 List after looking at C has [A, B, D, C]
	 
	 */
      using_syms[i] = check_ns_usings (symbol_names[i], block1);
    }
  
  /* Now that we have the complete list of usings we need to
     check if the symbol requested by the user could be an alias.
     e.g 
     
     namespace D { namespace Foo = A::B; }
     using namespace D;
     int main () {... };

     If the user is stopped in main and says  print Foo::a
     we need to look in namespace D to see if that aliases
     Foo to something. We then replace the symbol we need 
     to look for with A::B::a.
     We also lookup this symbol and if we find a local of this
     name (due to a using declaration) we return it.
     */
  
  for (i = 0; i < num_symbol_names; ++i)
    {
      if (!strcmp (real_name, actual_name))
	{
	  if ((TYPE_CPLUS_SPECIFIC(using_syms[i]->type))->aliases)
	    {
	      char *n = (char *) check_alias (actual_name, 
					      NULL, 
					      using_syms[i]->type);
	      if (strcmp (actual_name, n))
		{
		  actual_name = n;
		  sym = lookup_symbol_1 (n, block1, namespace, 
					 NULL, NULL, local);
		  add_new_names (actual_name, bl);
		  if (sym)
		    {
		      ns_symbols[num_ns_symbols++] = sym;
		      if (*local)
			return choose_symbol(*name, sym);
		    }			  
		  break;
		}
	    }
	}
      else
	break;
    }

  /* We now need to construct the whole list.
     e.g new_names contains A::D::a, B::a and C::a
     and from our list of using directives we have 
     E and B.
     the complete list of symbols to look for is
     B::a, C::a and 
     E::A::D::a, E::B::a, E::C::a,
     B::A::D::a, B::B::a, B::C::a 
     Since A::D::a could be a semi qualified name
     we need to prefix it with E and B. Similarly 
     B::a and C::a need to be prefixed with E And B.
   */  

  if (num_new_names)
    {
      k = num_symbol_names;
      
      /* We first take B::a from new_names - 
	 ( note the loop variable j starts from 1 not 0 
	 since we will add things to A::D::a later.)
	 and prefix it with the names already present
	 in symbol_names. i.e with E and B 
	 and append these 2 symbols to the list of symbol_names. 
	 We then take C::a from new_names and prefix it 
	 with E and B and append these symbols to the list.
	 
	 Note - num_symbol_names stays constant even though the
	 number of entries in symbol_names is increasing. 
	 k keeps a track of the real number of entries. 
       */

      for (j = 1; j < num_new_names; ++j)
	{
	  for (i = 0; i < num_symbol_names ; ++i)
	    {
	      /* Don't use j = 0 since we don't want the first one
		 it is the symbol that has been passed in */
	      char *full_name = xmalloc (strlen (symbol_names[i]) + 
					 strlen(new_names[j]) + 3);
	      full_name[0] = '\0';
	      sprintf(full_name, "%s%s%s", symbol_names[i], "::", new_names[j]);
	      if (k == using_alloc)
		{
		  symbol_names = (char **) xrealloc (symbol_names,
                                                   2 * using_alloc *
                                                   sizeof (char *));
		  using_alloc *= 2;
		}
	      symbol_names[k++] = full_name;
	    }
	}
      
      /* We then add B::a and C::a to the list */
      for (j = 1; j < num_new_names; ++j)
	{
	  if (k == using_alloc)
	    {
	      symbol_names = (char **) xrealloc (symbol_names,
					       2 * using_alloc *
					       sizeof (char *));
	      using_alloc *= 2;
	    }
	  symbol_names[k++] = strdup (new_names[j]);
	}
    }
  
  if (new_names) 
    {
      for (i = 0; i < num_new_names ; ++i)
	free (new_names[i]);
      free (new_names);
      new_names = NULL;
    }
  
  /* In the end we take A::D::a from new_names and prefix 
     that with the using directives.*/

  for (i = 0; i < num_symbol_names; ++i)
    {
      int len_name = strlen (symbol_names[i]);
      int len_actual = strlen (actual_name);
      char *new_name = xmalloc (len_name + len_actual + 3);
      new_name[0] = '\0';
      sprintf(new_name, "%s%s%s", symbol_names[i], "::", actual_name);
      symbol_names[i] = new_name;
   }

  /* If the array new_names is not empty it adds symbol names
     to the symbol_names array and so we need to change the 
     num_symbol_names variable */

  if (num_new_names)
    num_symbol_names = k;
  
  /* If actual_name is not the same as real_name you found a namespace
     alias for it and so we also need to look up the actual_name symbol.
     Add it to the end of the symbol_names array */
  if (strcmp (actual_name, real_name))
    {
      if (num_symbol_names == using_alloc)
	{
	  symbol_names = (char **) xrealloc (symbol_names,
					       2 * using_alloc *
					     sizeof (char *));
	  using_alloc *= 2;
	} 
      symbol_names[num_symbol_names++] = strdup (actual_name);   
    }
  /* Make sure to set this variable to 0 before returning
     since the array has been freed */
  num_new_names = 0;
  return 0;
}
