// -*- C++ -*-
// File: SO_Group.cpp

#include "ace/OS_NS_string.h"
#include "ace/OS_NS_unistd.h"
#include "ace/Log_Msg.h"
#include "ace/Process.h"
#include "ace/Pipe.h"

#include "Library.h"
#include "SO_Group.h"

SO_Group::SO_Group ()
  : undef_wrapper_ ("nothing"),
    undefs_(undef_wrapper_.imports()),
    libs_ (0),
    max_libs_ (128),
    num_libs_(0)
{
  libs_ = new Library*[max_libs_];
}

SO_Group::~SO_Group (void)
{
  for (int i = 0; i < num_libs_; delete libs_[i++])
    {
      // No action.
    }

  delete [] libs_;
}

void
SO_Group::add_executable (const char * path)
{
  ACE_Process proc;
  ACE_Process_Options opts;

  ACE_HANDLE pipe[2];
  ACE_Pipe io(pipe);

  opts.set_handles (ACE_STDIN,pipe[1]);

  int result = opts.command_line ("ldd %s",path);
  // Prevent compiler warning about "unused variable" if ACE_ASSERT is
  // an empty macro.
  ACE_UNUSED_ARG (result);
  ACE_ASSERT (result == 0);

  proc.spawn (opts);
  if (ACE_OS::close(pipe[1]) == -1)
    ACE_DEBUG ((LM_DEBUG, "%p\n", "close"));
  opts.release_handles();

  const int max_line_length = 1000;
  char line[max_line_length];

  while (true)
  {
    ACE_OS::memset (line,0,max_line_length);
    int len = 0;
    int nread = 0;
    int bogus = 0;

    // Skip initial whitespace.
    while ((nread = ACE_OS::read (pipe[0], line,1)) == 1
           && (*line == ' ' || *line == '\t'))
      {
        // No action.
      }

    if (nread != 1)
      {
        break;
      }

    // read the library name
    len = 1;

    while ((nread = ACE_OS::read (pipe[0], line + len, 1)) == 1
           && (line[len] != ' '))
      {
        if (! bogus && ++len == max_line_length)
          {
            bogus = 1;
            break;
          }
      }

    if (nread != 1 || bogus)
      {
        break;
      }

    line[len] = 0;
    char * dot = ACE_OS::strchr (line,'.');

    if (dot != 0)
      {
        *dot = 0;
      }

    char * libname = line + 3; // skip over "lib"

    // check to see if this is a new library
    int found = 0;

    for (int i = 0; !found && i < num_libs_; ++i)
      {
        found = (libs_[i]->name() == libname);
      }

    if (!found)
    {
      Library *nlib = new Library(libname);
      ACE_OS::memset (line,0,max_line_length);

      // Skip over '=> '.
      if (ACE_OS::read (pipe[0], line, 3) != 3)
        {
          break;
        }

      // get library path
      len = 0;

      while ((nread = ACE_OS::read(pipe[0],line + len,1)) == 1 &&
             (line[len] != ' '))
        {
          if (! bogus && ++len == max_line_length)
            {
              bogus = 1;
              break;
            }
        }

      if (nread != 1 || bogus)
        {
          break;
        }

      line[len] = 0;
      nlib->set_path (line);
      libs_[num_libs_++] = nlib;
      ACE_ASSERT (num_libs_ < max_libs_); // grow max libs?
    }

    // Skip the rest of the line.
    while ((nread = ACE_OS::read (pipe[0], line, 1)) == 1
           && *line != '\n')
      {
        // No action.
      }

    if (nread != 1)
      {
        break;
      }
  }
  proc.wait ();
  ACE_OS::close (pipe[0]);

  undef_wrapper_.add_source(path,1);
  // now do the ldd, iterate over the results to add new libs, etc.
}

void
SO_Group::analize (void)
{
  for (int passcount = 0; undefs_.modified (); ++passcount)
    {
      ACE_DEBUG ((LM_DEBUG,
                  "pass %d, undef count = %d\n",
                  passcount,
                  undefs_.size ()));

      for (int i = 0; i < num_libs_; libs_[i++]->resolve (undefs_))
        {
          // No action.
        }
    }
}

void
SO_Group::write_results (void)
{
  for (int i = 0; i < num_libs_; libs_[i++]->write_export_list (1))
    {
      // No action.
    }
}

void
SO_Group::load_modules (void)
{
  for (int i = 0; i < num_libs_; libs_[i++]->load_modules ())
    {
      // No action.
    }
}

void
SO_Group::list_libs (void)
{
  ACE_DEBUG ((LM_DEBUG, "Libs subject to analysis:\n"));

  for (int i = 0; i < num_libs_; ++i)
  {
    if (libs_[i]->has_modules ())
      {
        ACE_DEBUG ((LM_DEBUG, "  %s\n", libs_[i]->name ().c_str ()));
      }
  }
}







