// archive.h -- archive support for gold      -*- C++ -*-

#ifndef GOLD_ARCHIVE_H
#define GOLD_ARCHIVE_H

#include <string>
#include <vector>

#include "workqueue.h"

namespace gold
{

class Input_file;
class Input_objects;
class Layout;
class Symbol_table;

// This class represents an archive--generally a libNAME.a file.
// Archives have a symbol table and a list of objects.

class Archive
{
 public:
  Archive(const std::string& name, Input_file* input_file)
    : name_(name), input_file_(input_file), armap_(), extended_names_()
  { }

  // The length of the magic string at the start of an archive.
  static const int sarmag = 8;

  // The magic string at the start of an archive.
  static const char armag[sarmag];

  // The string expected at the end of an archive member header.
  static const char arfmag[2];

  // The name of the object.
  const std::string&
  name() const
  { return this->name_; }

  // Set up the archive: read the symbol map.
  void
  setup();

  // Lock the underlying file.
  void
  lock()
  { this->input_file_->file().lock(); }

  // Unlock the underlying file.
  void
  unlock()
  { this->input_file_->file().unlock(); }

  // Return whether the underlying file is locked.
  bool
  is_locked() const
  { return this->input_file_->file().is_locked(); }

  // Select members from the archive as needed and add them to the
  // link.
  void
  add_symbols(Symbol_table*, Layout*, Input_objects*);

 private:
  Archive(const Archive&);
  Archive& operator=(const Archive&);

  struct Archive_header;
  class Add_archive_symbols_locker;

  // Get a view into the underlying file.
  const unsigned char*
  get_view(off_t start, off_t size);

  // Read an archive member header at OFF.  Return the size of the
  // member, and set *PNAME to the name.
  off_t
  read_header(off_t off, std::string* pname);

  // Include an archive member in the link.
  void
  include_member(Symbol_table*, Layout*, Input_objects*, off_t off);

  // An entry in the archive map of symbols to object files.
  struct Armap_entry
  {
    // The symbol name.
    const char* name;
    // The offset to the file.
    off_t offset;
  };

  // Name of object as printed to user.
  std::string name_;
  // For reading the file.
  Input_file* input_file_;
  // The archive map.
  std::vector<Armap_entry> armap_;
  // The extended name table.
  std::string extended_names_;
};

// This class is used to read an archive and pick out the desired
// elements and add them to the link.

class Add_archive_symbols : public Task
{
 public:
  Add_archive_symbols(Symbol_table* symtab, Layout* layout,
		      Input_objects* input_objects,
		      Archive* archive, Task_token* this_blocker,
		      Task_token* next_blocker)
    : symtab_(symtab), layout_(layout), input_objects_(input_objects),
      archive_(archive), this_blocker_(this_blocker),
      next_blocker_(next_blocker)
  { }

  ~Add_archive_symbols();

  // The standard Task methods.

  Is_runnable_type
  is_runnable(Workqueue*);

  Task_locker*
  locks(Workqueue*);

  void
  run(Workqueue*);

 private:
  class Add_archive_symbols_locker;

  Symbol_table* symtab_;
  Layout* layout_;
  Input_objects* input_objects_;
  Archive* archive_;
  Task_token* this_blocker_;
  Task_token* next_blocker_;
};

} // End namespace gold.

#endif // !defined(GOLD_ARCHIVE_H)