//===-- llvm/Bytecode/Archive.h - LLVM Bytecode Archive ---------*- C++ -*-===//
// 
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Reid Spencer and is distributed under the 
// University of Illinois Open Source License. See LICENSE.TXT for details.
// 
//===----------------------------------------------------------------------===//
//
// This header file defines the interface to LLVM Archive files. The interface
// is provided by the Archive class implemented by the lib/Bytecode/Archive
// library.  This library is used to read and write archive (*.a) files that 
// contain LLVM bytecode files (or others). It provides rudimentary capabilities 
// to construct an archive file from a set of files, read the archive members 
// into memory, search the archive for member files that fulfill unresolved 
// symbols, and extract the archive back to the file system.  Full 
// symbol table support is provided for loading only those files that resolve 
// symbols. Note that read performance of this library is _crucial_ for 
// performance of JIT type applications and the linkers. Consequently, the 
// library is optimized for reading.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_BYTECODE_ARCHIVE_H
#define LLVM_BYTECODE_ARCHIVE_H

#include "llvm/System/Path.h"
#include <map>

namespace llvm {

class ModuleProvider;
class Module;

/// This class represents an archive file. It abstracts away the file format,
/// and logical operations that can be done on an archive file. It also provides
/// utilities for controlling the runtime loading/reading of the archive file
/// to provide efficient access mechanisms for JIT systems and linkers.
class Archive {

  /// @name Types
  /// @{
  public:
    /// The user's interface to the archive symbol table. This multimap allows
    /// symbols to be looked up and modules to be instantiated from the file
    /// lazily via the ModuleProvider::materializeModule method.
    typedef std::map<std::string,ModuleProvider*> SymTab;

    /// This typedef is just shorthand for a vector of Path names
    typedef std::vector<sys::Path> PathList;

    /// This typedef is just shorthand for a vector of Modules
    typedef std::vector<Module*> ModuleList;

  /// @}
  /// @name Constructors
  /// @{
  public:
    /// Create an empty archive file, \p Filename. The returned Archive object
    /// will have no file members and an empty symbol table. The actual archive
    /// file is not created until the returned Archive object is destructed.
    /// @throws std::string if an error occurs
    /// @returns An Archive* that represents the new archive file.
    /// @brief Create an empty archive file.
    static Archive* CreateEmpty(
      const sys::Path& Filename        ///< Name of archive file
    );

#if 0

This interface severely complicates the
Archive class. Its commented out until
a final determination is made of whether
we will support adding modules or not.

    /// Create a new archive file, \p Filename, from the LLVM modules \p Modules.
    /// The module's externally visible linkage symbols will be added to the 
    /// archive's symbol table.  The names of the file members will be obtained 
    /// from the Module::getModuleId() method. If that name is not unique, it will
    /// be made unique by appending a monotonically increasing integer to it. If 
    /// \p StripName is non-empty, it specifies a prefix to be stripped from the 
    /// name of the file members. This allows archives with relative path names 
    /// to be created. The actual archive file is not created until the
    /// returned Archive object is destructed. 
    /// @returns An Archive* that that represents the newly created archive file. 
    /// @throws std::string if an error occurs
    /// @brief Create an archive file from modules.
    static Archive* CreateFromModules(
      const sys::Path& Filename,       ///< Name of archive file
      const ModuleList& Modules,       ///< Modules to be put in archive
      const std::string& StripName=""  ///< Prefix to strip from member names
    );
#endif

    /// Create a new archive file, \p Filename, from a set of existing \p Files.
    /// Each entry in \p Files will be added to the archive. If any file is an
    /// llvm bytecode file, its externally visible linkage symbols will be added
    /// to the archive's symbol table. If any of the paths in \p Files refer to
    /// directories, those directories will be ignored. Full path names to 
    /// files must be provided. However, if \p StripName is non-empty, it 
    /// specifies a prefix string to be removed from each path before it is 
    /// written as the name of the file member. Any path names that do not have 
    /// the \p StripName as a prefix will be saved with the full path name
    /// provided in \p Files. This permits archives relative to a top level 
    /// directory to be created.
    /// @throws std::string if an error occurs
    /// @brief Create an archive file from files.
    static Archive* CreateFromFiles(
      const sys::Path& Filename,       ///< Name of archive file
      const PathList& Files,           ///< File paths to be put in archive
      const std::string& StripName=""  ///< Prefix path name to strip from names
    );

    /// Open an existing archive file from \p Filename. The necessary
    /// arrangements to read the file are made, but nothing much is actually 
    /// read from the file. Use the Accessor methods below to lazily obtain 
    /// those portions of the file that are of interest.
    /// @throws std::string if an error occurs
    /// @brief Open an existing archive.
    static Archive* Open(
      const sys::Path& Filename       ///< Name of the archive file
    );

    /// This destructor "finalizes" the archive. Regardless of whether the 
    /// archive was created or opened, all memory associated with the archive 
    /// is released, including any SymTab* returned by the getSymbolTable()
    /// method, any ModuleProviders and their associated Modules returned by
    /// any interface method, etc.  Additionally, if the archive was created
    /// using one of the Create* methods, the archive is written to disk in
    /// its final format. After this method exits, none of the memory 
    /// associated with the archive is valid. It is the user's responsibility 
    /// to ensure that all references to such memory is removed before the
    /// Archive is destructed.
    /// @throws std::string if an error occurs
    /// @brief Destruct in-memory archive 
    ~Archive();

  /// @}
  /// @name Accessors
  /// @{
  public:
    /// This accessor looks up the \p symbol in the archive's symbol table and 
    /// returns the associated module that defines that symbol. This method can
    /// be called as many times as necessary. This is handy for linking the 
    /// archive into another module based on unresolved symbols. Note that the
    /// ModuleProvider returned by this accessor should not be deleted by the
    /// caller. It is managed internally by the Archive class. It is possible 
    /// that multiple calls to this accessor will return the same ModuleProvider
    /// instance because the associated module defines multiple symbols. 
    /// @throws std::string if an error occurs
    /// @returns The ModuleProvider* found or null if the archive does not 
    /// contain a module that defines the \p symbol.
    /// @brief Look up a module by symbol name.
    ModuleProvider* findModuleContainingSymbol(
      const std::string& symbol        ///< Symbol to be sought
    ) const;

    /// Return the list of all the \p Paths for the file members in the archive.
    /// This is handy for generating the table of contents of the archive. Note
    /// that \p Paths is *not* cleared before it is populated. New entries are 
    /// appended to the end of the PathList.
    /// @throw std::string if an error occurs
    /// @returns nothing
    /// @brief Get all the paths in the archive
    void getAllPaths(
      PathList& Paths                ///< The list of paths returned
    );

    /// This method returns a caller readable SymTab object which is a map
    /// of symbol names to ModuleProviders. Callers can traverse this symbol
    /// table, look up specific symbols, etc. and materialize any Modules they 
    /// want with the associated ModuleProviders.  It is unnecessary to call
    /// this accessor more than once as the same object is alway returned, even
    /// if changes have been made.
    /// @returns a constant SymTab* that is the same for every invocation. The
    /// caller should not attempt to free or modify this SymTab object, just use
    /// it. 
    /// @brief Get the archive's symbol table.
    const SymTab* getSymbolTable();

    /// Extract the contents of the archive back to the file system using \p
    /// RootDir as the directory at the root of the extraction.  Each file 
    /// member is written back as a separate file. If \p flat is false, then
    /// directories are created as necessary to restore the files to the correct
    /// sub-directory of \p root as specified in the full path of the file
    /// member. Otherwise, paths are ignored and all file members will be 
    /// extracted to the \p root directory using only the filename portion of
    /// the path (directories ignored). If \p symtab is true, the archive's
    /// symbol table will also be extracted to a file named __SYMTAB.
    /// @returns nothing
    /// @throws std::string if an error occurs
    /// @brief Extract archive contents to a file.
    void extractAllToDirectory(
      const sys::Path& RootDir,      ///< The root directory for extraction 
      bool Flat = true,              ///< false = recreate directory structure
      bool Symtab = false            ///< true = extract symbol table too
    );

    /// Extract one file in the archive back to the file system using \p RootDir
    /// as the directory at the root of the extraction. The file \p name is 
    /// extracted and placed into \p RootDir. If \p Flat is false, then any
    /// intermediate directory names in the file member's path will also be
    /// created. Otherwise, the member's file is created in RootDir ignoring
    /// the leading path and using only the member's file name.
    /// @throws std::string if an error occurs.
    /// @returns nothing
    /// @brief Extract a single archive file.
    void extractOneFileToDirectory(
      const sys::Path& RootDir,      ///< The root directory for extraction
      const sys::Path& name,         ///< Name of file to extract
      bool Flat = true               ///< false = recreate directories
    );

  /// @}
  /// @name Mutators
  /// @{
  public:
    /// Each entry in \p Files will be added to the archive. If any file is an
    /// llvm bytecode file, its externally visible linkage symbols will be added
    /// to the archive's symbol table. If any of the paths in \p Files refer to
    /// directories, those directories will be ignored. Full path names to 
    /// files must be provided. However, if \p StripName is non-empty, it 
    /// specifies a prefix string to be removed from each path before it is 
    /// written as the name of the file member. Any path names that do not have 
    /// the \p StripName as a prefix will be saved with the full path name
    /// provided. This permits archives relative to a top level directory 
    /// to be created.
    /// @throws std::string if an error occurs
    /// @returns nothing
    /// @brief Add a set of files to the archive.
    void addFiles(
      const PathList& Files,           ///< The names of files to add to archive
      const std::string& StripName=""  ///< Prefix path to strip from names
    );

#if 0

This interface severely complicates the
Archive class. Its commented out until
a final determination is made of whether
we will support adding modules or not.

    /// Add a set of Modules to the archive.  Names of member files will
    /// be taken from the Module identifier (Module::getModuleIdentifier) if it
    /// is unique. Non-unique member names will be made unique by appending a 
    /// number. The symbol table will be augmented with the global symbols of 
    /// all the modules provided. If \p StripName is non-empty, it 
    /// specifies a prefix string to be removed from each moduleId  before it is 
    /// written as the name of the file member. Any path names that do not have 
    /// the \p StripName as a prefix will be saved with the full path name
    /// provided. This permits archives relative to a top level directory  to
    /// be created.
    /// @throws std::string if an error occurs
    /// @returns nothing
    /// @brief Add a set of modules to the archive.
    void addModules(
      const ModuleList& Modules,       ///< The modules to add to the archive
      const std::string& StripName=""  ///< Prefix path to strip from names
    );
#endif

  /// @}
  /// @name Data
  /// @{
  private:
    class ArchiveInternals;
    ArchiveInternals* impl;   ///< Implementation class
  /// @}
  /// @name Hidden
  /// @{
  private:
    Archive();                          ///< Do not implement
    Archive(const Archive&);            ///< Do not implement
    Archive& operator=(const Archive&); ///< Do not implement
  /// @}
};

} // End llvm namespace

// vim: sw=2 ai 

#endif
