166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman//===-- llvm-ar.cpp - LLVM archive librarian utility ----------------------===//
266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman//
366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman//                     The LLVM Compiler Infrastructure
466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman//
566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// This file is distributed under the University of Illinois Open Source
666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// License. See LICENSE.TXT for details.
766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman//
866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman//===----------------------------------------------------------------------===//
966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman//
1066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// Builds up (relatively) standard unix archive files (.a) containing LLVM
1166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// bitcode or other files.
1266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman//
1366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman//===----------------------------------------------------------------------===//
1466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
1566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman#include "llvm/LLVMContext.h"
1666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman#include "llvm/Module.h"
1766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman#include "llvm/Bitcode/Archive.h"
1866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman#include "llvm/Support/CommandLine.h"
1966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman#include "llvm/Support/FileSystem.h"
2066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman#include "llvm/Support/ManagedStatic.h"
2166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman#include "llvm/Support/PrettyStackTrace.h"
2266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman#include "llvm/Support/Format.h"
2366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman#include "llvm/Support/raw_ostream.h"
2466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman#include "llvm/Support/Signals.h"
2566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman#include <algorithm>
2666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman#include <memory>
2766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman#include <fstream>
2866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanusing namespace llvm;
2966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
3066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// Option for compatibility with AIX, not used but must allow it to be present.
3166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanstatic cl::opt<bool>
3266b8ab22586debccb1f787d4d52b7f042d4ddeb8John BaumanX32Option ("X32_64", cl::Hidden,
3366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman            cl::desc("Ignored option for compatibility with AIX"));
3466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
3566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// llvm-ar operation code and modifier flags. This must come first.
3666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanstatic cl::opt<std::string>
3766b8ab22586debccb1f787d4d52b7f042d4ddeb8John BaumanOptions(cl::Positional, cl::Required, cl::desc("{operation}[modifiers]..."));
3866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
3966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// llvm-ar remaining positional arguments.
4066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanstatic cl::list<std::string>
4166b8ab22586debccb1f787d4d52b7f042d4ddeb8John BaumanRestOfArgs(cl::Positional, cl::OneOrMore,
4266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    cl::desc("[relpos] [count] <archive-file> [members]..."));
4366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
4466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// MoreHelp - Provide additional help output explaining the operations and
4566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// modifiers of llvm-ar. This object instructs the CommandLine library
4666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// to print the text of the constructor when the --help option is given.
4766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanstatic cl::extrahelp MoreHelp(
4866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "\nOPERATIONS:\n"
4966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  d[NsS]       - delete file(s) from the archive\n"
5066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  m[abiSs]     - move file(s) in the archive\n"
5166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  p[kN]        - print file(s) found in the archive\n"
5266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  q[ufsS]      - quick append file(s) to the archive\n"
5366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  r[abfiuzRsS] - replace or insert file(s) into the archive\n"
5466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  t            - display contents of archive\n"
5566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  x[No]        - extract file(s) from the archive\n"
5666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "\nMODIFIERS (operation specific):\n"
5766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  [a] - put file(s) after [relpos]\n"
5866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  [b] - put file(s) before [relpos] (same as [i])\n"
5966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  [f] - truncate inserted file names\n"
6066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  [i] - put file(s) before [relpos] (same as [b])\n"
6166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  [k] - always print bitcode files (default is to skip them)\n"
6266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  [N] - use instance [count] of name\n"
6366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  [o] - preserve original dates\n"
6466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  [P] - use full path names when matching\n"
6566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  [R] - recurse through directories when inserting\n"
6666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  [s] - create an archive index (cf. ranlib)\n"
6766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  [S] - do not build a symbol table\n"
6866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  [u] - update only files newer than archive contents\n"
6966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  [z] - compress files before inserting/extracting\n"
7066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "\nMODIFIERS (generic):\n"
7166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  [c] - do not warn if the library had to be created\n"
7266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  [v] - be verbose about actions taken\n"
7366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  "  [V] - be *really* verbose about actions taken\n"
7466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman);
7566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
7666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// This enumeration delineates the kinds of operations on an archive
7766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// that are permitted.
7866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanenum ArchiveOperation {
7966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  NoOperation,      ///< An operation hasn't been specified
8066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  Print,            ///< Print the contents of the archive
8166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  Delete,           ///< Delete the specified members
8266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  Move,             ///< Move members to end or as given by {a,b,i} modifiers
8366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  QuickAppend,      ///< Quickly append to end of archive
8466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  ReplaceOrInsert,  ///< Replace or Insert members
8566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  DisplayTable,     ///< Display the table of contents
8666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  Extract           ///< Extract files back to file system
8766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman};
8866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
8966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// Modifiers to follow operation to vary behavior
9066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool AddAfter = false;           ///< 'a' modifier
9166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool AddBefore = false;          ///< 'b' modifier
9266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool Create = false;             ///< 'c' modifier
9366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool TruncateNames = false;      ///< 'f' modifier
9466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool InsertBefore = false;       ///< 'i' modifier
9566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool DontSkipBitcode = false;    ///< 'k' modifier
9666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool UseCount = false;           ///< 'N' modifier
9766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool OriginalDates = false;      ///< 'o' modifier
9866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool FullPath = false;           ///< 'P' modifier
9966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool RecurseDirectories = false; ///< 'R' modifier
10066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool SymTable = true;            ///< 's' & 'S' modifiers
10166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool OnlyUpdate = false;         ///< 'u' modifier
10266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool Verbose = false;            ///< 'v' modifier
10366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool ReallyVerbose = false;      ///< 'V' modifier
10466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool Compression = false;        ///< 'z' modifier
10566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
10666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// Relative Positional Argument (for insert/move). This variable holds
10766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// the name of the archive member to which the 'a', 'b' or 'i' modifier
10866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// refers. Only one of 'a', 'b' or 'i' can be specified so we only need
10966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// one variable.
11066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanstd::string RelPos;
11166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
11266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// Select which of multiple entries in the archive with the same name should be
11366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// used (specified with -N) for the delete and extract operations.
11466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanint Count = 1;
11566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
11666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// This variable holds the name of the archive file as given on the
11766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// command line.
11866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanstd::string ArchiveName;
11966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
12066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// This variable holds the list of member files to proecess, as given
12166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// on the command line.
12266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanstd::vector<std::string> Members;
12366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
12466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// This variable holds the (possibly expanded) list of path objects that
12566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// correspond to files we will
12666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanstd::set<sys::Path> Paths;
12766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
12866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// The Archive object to which all the editing operations will be sent.
12966b8ab22586debccb1f787d4d52b7f042d4ddeb8John BaumanArchive* TheArchive = 0;
13066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
13166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// getRelPos - Extract the member filename from the command line for
13266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// the [relpos] argument associated with a, b, and i modifiers
13366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanvoid getRelPos() {
13466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if(RestOfArgs.size() > 0) {
13566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    RelPos = RestOfArgs[0];
13666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    RestOfArgs.erase(RestOfArgs.begin());
13766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  }
13866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  else
13966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    throw "Expected [relpos] for a, b, or i modifier";
14066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman}
14166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
14266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// getCount - Extract the [count] argument associated with the N modifier
14366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// from the command line and check its value.
14466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanvoid getCount() {
14566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if(RestOfArgs.size() > 0) {
14666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    Count = atoi(RestOfArgs[0].c_str());
14766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    RestOfArgs.erase(RestOfArgs.begin());
14866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  }
14966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  else
15066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    throw "Expected [count] value with N modifier";
15166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
15266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Non-positive counts are not allowed
15366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (Count < 1)
15466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    throw "Invalid [count] value (not a positive integer)";
15566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman}
15666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
15766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// getArchive - Get the archive file name from the command line
15866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanvoid getArchive() {
15966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if(RestOfArgs.size() > 0) {
16066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    ArchiveName = RestOfArgs[0];
16166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    RestOfArgs.erase(RestOfArgs.begin());
16266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  }
16366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  else
16466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    throw "An archive name must be specified.";
16566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman}
16666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
16766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// getMembers - Copy over remaining items in RestOfArgs to our Members vector
16866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// This is just for clarity.
16966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanvoid getMembers() {
17066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if(RestOfArgs.size() > 0)
17166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    Members = std::vector<std::string>(RestOfArgs);
17266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman}
17366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
17466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// parseCommandLine - Parse the command line options as presented and return the
17566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// operation specified. Process all modifiers and check to make sure that
17666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// constraints on modifier/operation pairs have not been violated.
17766b8ab22586debccb1f787d4d52b7f042d4ddeb8John BaumanArchiveOperation parseCommandLine() {
17866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
17966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Keep track of number of operations. We can only specify one
18066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // per execution.
18166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  unsigned NumOperations = 0;
18266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
18366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Keep track of the number of positional modifiers (a,b,i). Only
18466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // one can be specified.
18566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  unsigned NumPositional = 0;
18666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
18766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Keep track of which operation was requested
18866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  ArchiveOperation Operation = NoOperation;
18966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
19066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  for(unsigned i=0; i<Options.size(); ++i) {
19166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    switch(Options[i]) {
19266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'd': ++NumOperations; Operation = Delete; break;
19366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'm': ++NumOperations; Operation = Move ; break;
19466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'p': ++NumOperations; Operation = Print; break;
19566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'q': ++NumOperations; Operation = QuickAppend; break;
19666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'r': ++NumOperations; Operation = ReplaceOrInsert; break;
19766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 't': ++NumOperations; Operation = DisplayTable; break;
19866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'x': ++NumOperations; Operation = Extract; break;
19966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'c': Create = true; break;
20066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'f': TruncateNames = true; break;
20166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'k': DontSkipBitcode = true; break;
20266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'l': /* accepted but unused */ break;
20366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'o': OriginalDates = true; break;
20466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'P': FullPath = true; break;
20566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'R': RecurseDirectories = true; break;
20666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 's': SymTable = true; break;
20766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'S': SymTable = false; break;
20866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'u': OnlyUpdate = true; break;
20966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'v': Verbose = true; break;
21066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'V': Verbose = ReallyVerbose = true; break;
21166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'z': Compression = true; break;
21266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'a':
21366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      getRelPos();
21466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      AddAfter = true;
21566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      NumPositional++;
21666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      break;
21766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'b':
21866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      getRelPos();
21966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      AddBefore = true;
22066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      NumPositional++;
22166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      break;
22266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'i':
22366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      getRelPos();
22466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      InsertBefore = true;
22566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      NumPositional++;
22666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      break;
22766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    case 'N':
22866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      getCount();
22966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      UseCount = true;
23066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      break;
23166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    default:
23266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      cl::PrintHelpMessage();
23366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    }
23466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  }
23566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
23666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // At this point, the next thing on the command line must be
23766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // the archive name.
23866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  getArchive();
23966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
24066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Everything on the command line at this point is a member.
24166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  getMembers();
24266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
24366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Perform various checks on the operation/modifier specification
24466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // to make sure we are dealing with a legal request.
24566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (NumOperations == 0)
24666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    throw "You must specify at least one of the operations";
24766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (NumOperations > 1)
24866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    throw "Only one operation may be specified";
24966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (NumPositional > 1)
25066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    throw "You may only specify one of a, b, and i modifiers";
25166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (AddAfter || AddBefore || InsertBefore)
25266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    if (Operation != Move && Operation != ReplaceOrInsert)
25366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      throw "The 'a', 'b' and 'i' modifiers can only be specified with "
25466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman            "the 'm' or 'r' operations";
25566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (RecurseDirectories && Operation != ReplaceOrInsert)
25666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    throw "The 'R' modifiers is only applicabe to the 'r' operation";
25766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (OriginalDates && Operation != Extract)
25866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    throw "The 'o' modifier is only applicable to the 'x' operation";
25966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (TruncateNames && Operation!=QuickAppend && Operation!=ReplaceOrInsert)
26066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    throw "The 'f' modifier is only applicable to the 'q' and 'r' operations";
26166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (OnlyUpdate && Operation != ReplaceOrInsert)
26266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    throw "The 'u' modifier is only applicable to the 'r' operation";
26366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (Compression && Operation!=ReplaceOrInsert && Operation!=Extract)
26466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    throw "The 'z' modifier is only applicable to the 'r' and 'x' operations";
26566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (Count > 1 && Members.size() > 1)
26666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    throw "Only one member name may be specified with the 'N' modifier";
26766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
26866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Return the parsed operation to the caller
26966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  return Operation;
27066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman}
27166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
27266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// recurseDirectories - Implements the "R" modifier. This function scans through
27366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// the Paths vector (built by buildPaths, below) and replaces any directories it
27466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// finds with all the files in that directory (recursively). It uses the
27566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// sys::Path::getDirectoryContent method to perform the actual directory scans.
27666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool
27766b8ab22586debccb1f787d4d52b7f042d4ddeb8John BaumanrecurseDirectories(const sys::Path& path,
27866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman                   std::set<sys::Path>& result, std::string* ErrMsg) {
27966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  result.clear();
28066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (RecurseDirectories) {
28166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    std::set<sys::Path> content;
28266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    if (path.getDirectoryContents(content, ErrMsg))
28366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      return true;
28466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
28566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    for (std::set<sys::Path>::iterator I = content.begin(), E = content.end();
28666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman         I != E; ++I) {
28766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      // Make sure it exists and is a directory
28866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      sys::PathWithStatus PwS(*I);
28966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      const sys::FileStatus *Status = PwS.getFileStatus(false, ErrMsg);
29066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (!Status)
29166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        return true;
29266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (Status->isDir) {
29366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        std::set<sys::Path> moreResults;
29466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        if (recurseDirectories(*I, moreResults, ErrMsg))
29566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          return true;
29666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        result.insert(moreResults.begin(), moreResults.end());
29766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      } else {
29866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          result.insert(*I);
29966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      }
30066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    }
30166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  }
30266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  return false;
30366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman}
30466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
30566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// buildPaths - Convert the strings in the Members vector to sys::Path objects
30666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// and make sure they are valid and exist exist. This check is only needed for
30766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// the operations that add/replace files to the archive ('q' and 'r')
30866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool buildPaths(bool checkExistence, std::string* ErrMsg) {
30966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  for (unsigned i = 0; i < Members.size(); i++) {
31066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    sys::Path aPath;
31166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    if (!aPath.set(Members[i]))
31266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      throw std::string("File member name invalid: ") + Members[i];
31366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    if (checkExistence) {
31466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      bool Exists;
31566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (sys::fs::exists(aPath.str(), Exists) || !Exists)
31666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        throw std::string("File does not exist: ") + Members[i];
31766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      std::string Err;
31866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      sys::PathWithStatus PwS(aPath);
31966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      const sys::FileStatus *si = PwS.getFileStatus(false, &Err);
32066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (!si)
32166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        throw Err;
32266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (si->isDir) {
32366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        std::set<sys::Path> dirpaths;
32466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        if (recurseDirectories(aPath, dirpaths, ErrMsg))
32566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          return true;
32666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        Paths.insert(dirpaths.begin(),dirpaths.end());
32766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      } else {
32866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        Paths.insert(aPath);
32966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      }
33066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    } else {
33166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      Paths.insert(aPath);
33266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    }
33366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  }
33466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  return false;
33566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman}
33666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
33766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// printSymbolTable - print out the archive's symbol table.
33866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanvoid printSymbolTable() {
33966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  outs() << "\nArchive Symbol Table:\n";
34066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  const Archive::SymTabType& symtab = TheArchive->getSymbolTable();
34166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  for (Archive::SymTabType::const_iterator I=symtab.begin(), E=symtab.end();
34266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman       I != E; ++I ) {
34366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    unsigned offset = TheArchive->getFirstFileOffset() + I->second;
34466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    outs() << " " << format("%9u", offset) << "\t" << I->first <<"\n";
34566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  }
34666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman}
34766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
34866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// doPrint - Implements the 'p' operation. This function traverses the archive
34966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// looking for members that match the path list. It is careful to uncompress
35066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// things that should be and to skip bitcode files unless the 'k' modifier was
35166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// given.
35266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool doPrint(std::string* ErrMsg) {
35366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (buildPaths(false, ErrMsg))
35466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    return true;
35566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  unsigned countDown = Count;
35666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
35766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman       I != E; ++I ) {
35866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    if (Paths.empty() ||
35966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) {
36066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (countDown == 1) {
36166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        const char* data = reinterpret_cast<const char*>(I->getData());
36266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
36366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        // Skip things that don't make sense to print
36466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        if (I->isLLVMSymbolTable() || I->isSVR4SymbolTable() ||
36566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman            I->isBSD4SymbolTable() || (!DontSkipBitcode && I->isBitcode()))
36666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          continue;
36766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
36866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        if (Verbose)
36966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          outs() << "Printing " << I->getPath().str() << "\n";
37066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
37166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        unsigned len = I->getSize();
37266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        outs().write(data, len);
37366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      } else {
37466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        countDown--;
37566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      }
37666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    }
37766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  }
37866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  return false;
37966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman}
38066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
38166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// putMode - utility function for printing out the file mode when the 't'
38266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// operation is in verbose mode.
38366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanvoid
38466b8ab22586debccb1f787d4d52b7f042d4ddeb8John BaumanprintMode(unsigned mode) {
38566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (mode & 004)
38666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    outs() << "r";
38766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  else
38866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    outs() << "-";
38966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (mode & 002)
39066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    outs() << "w";
39166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  else
39266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    outs() << "-";
39366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (mode & 001)
39466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    outs() << "x";
39566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  else
39666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    outs() << "-";
39766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman}
39866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
39966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// doDisplayTable - Implement the 't' operation. This function prints out just
40066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// the file names of each of the members. However, if verbose mode is requested
40166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// ('v' modifier) then the file type, permission mode, user, group, size, and
40266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// modification time are also printed.
40366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool
40466b8ab22586debccb1f787d4d52b7f042d4ddeb8John BaumandoDisplayTable(std::string* ErrMsg) {
40566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (buildPaths(false, ErrMsg))
40666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    return true;
40766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
40866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman       I != E; ++I ) {
40966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    if (Paths.empty() ||
41066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) {
41166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (Verbose) {
41266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        // FIXME: Output should be this format:
41366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        // Zrw-r--r--  500/ 500    525 Nov  8 17:42 2004 Makefile
41466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        if (I->isBitcode())
41566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          outs() << "b";
41666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        else if (I->isCompressed())
41766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          outs() << "Z";
41866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        else
41966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          outs() << " ";
42066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        unsigned mode = I->getMode();
42166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        printMode((mode >> 6) & 007);
42266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        printMode((mode >> 3) & 007);
42366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        printMode(mode & 007);
42466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        outs() << " " << format("%4u", I->getUser());
42566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        outs() << "/" << format("%4u", I->getGroup());
42666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        outs() << " " << format("%8u", I->getSize());
42766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        outs() << " " << format("%20s", I->getModTime().str().substr(4).c_str());
42866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        outs() << " " << I->getPath().str() << "\n";
42966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      } else {
43066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        outs() << I->getPath().str() << "\n";
43166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      }
43266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    }
43366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  }
43466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (ReallyVerbose)
43566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    printSymbolTable();
43666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  return false;
43766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman}
43866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
43966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// doExtract - Implement the 'x' operation. This function extracts files back to
44066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// the file system, making sure to uncompress any that were compressed
44166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool
44266b8ab22586debccb1f787d4d52b7f042d4ddeb8John BaumandoExtract(std::string* ErrMsg) {
44366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (buildPaths(false, ErrMsg))
44466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    return true;
44566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
44666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman       I != E; ++I ) {
44766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    if (Paths.empty() ||
44866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) {
44966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
45066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      // Make sure the intervening directories are created
45166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (I->hasPath()) {
45266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        sys::Path dirs(I->getPath());
45366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        dirs.eraseComponent();
45466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        if (dirs.createDirectoryOnDisk(/*create_parents=*/true, ErrMsg))
45566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          return true;
45666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      }
45766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
45866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      // Open up a file stream for writing
45966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      std::ios::openmode io_mode = std::ios::out | std::ios::trunc |
46066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman                                   std::ios::binary;
46166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      std::ofstream file(I->getPath().c_str(), io_mode);
46266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
46366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      // Get the data and its length
46466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      const char* data = reinterpret_cast<const char*>(I->getData());
46566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      unsigned len = I->getSize();
46666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
46766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      // Write the data.
46866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      file.write(data,len);
46966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      file.close();
47066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
47166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      // If we're supposed to retain the original modification times, etc. do so
47266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      // now.
47366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (OriginalDates)
47466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        I->getPath().setStatusInfoOnDisk(I->getFileStatus());
47566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    }
47666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  }
47766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  return false;
47866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman}
47966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
48066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// doDelete - Implement the delete operation. This function deletes zero or more
48166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// members from the archive. Note that if the count is specified, there should
48266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// be no more than one path in the Paths list or else this algorithm breaks.
48366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// That check is enforced in parseCommandLine (above).
48466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool
48566b8ab22586debccb1f787d4d52b7f042d4ddeb8John BaumandoDelete(std::string* ErrMsg) {
48666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (buildPaths(false, ErrMsg))
48766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    return true;
48866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (Paths.empty())
48966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    return false;
49066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  unsigned countDown = Count;
49166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
49266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman       I != E; ) {
49366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    if (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end()) {
49466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (countDown == 1) {
49566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        Archive::iterator J = I;
49666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        ++I;
49766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        TheArchive->erase(J);
49866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      } else
49966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        countDown--;
50066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    } else {
50166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      ++I;
50266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    }
50366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  }
50466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
50566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // We're done editting, reconstruct the archive.
50666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (TheArchive->writeToDisk(SymTable,TruncateNames,Compression,ErrMsg))
50766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    return true;
50866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (ReallyVerbose)
50966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    printSymbolTable();
51066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  return false;
51166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman}
51266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
51366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// doMore - Implement the move operation. This function re-arranges just the
51466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// order of the archive members so that when the archive is written the move
51566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// of the members is accomplished. Note the use of the RelPos variable to
51666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// determine where the items should be moved to.
51766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool
51866b8ab22586debccb1f787d4d52b7f042d4ddeb8John BaumandoMove(std::string* ErrMsg) {
51966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (buildPaths(false, ErrMsg))
52066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    return true;
52166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
52266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // By default and convention the place to move members to is the end of the
52366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // archive.
52466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  Archive::iterator moveto_spot = TheArchive->end();
52566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
52666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // However, if the relative positioning modifiers were used, we need to scan
52766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // the archive to find the member in question. If we don't find it, its no
52866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // crime, we just move to the end.
52966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (AddBefore || InsertBefore || AddAfter) {
53066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end();
53166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman         I != E; ++I ) {
53266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (RelPos == I->getPath().str()) {
53366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        if (AddAfter) {
53466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          moveto_spot = I;
53566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          moveto_spot++;
53666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        } else {
53766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          moveto_spot = I;
53866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        }
53966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        break;
54066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      }
54166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    }
54266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  }
54366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
54466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Keep a list of the paths remaining to be moved
54566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  std::set<sys::Path> remaining(Paths);
54666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
54766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Scan the archive again, this time looking for the members to move to the
54866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // moveto_spot.
54966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end();
55066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman       I != E && !remaining.empty(); ++I ) {
55166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    std::set<sys::Path>::iterator found =
55266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      std::find(remaining.begin(),remaining.end(),I->getPath());
55366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    if (found != remaining.end()) {
55466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (I != moveto_spot)
55566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        TheArchive->splice(moveto_spot,*TheArchive,I);
55666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      remaining.erase(found);
55766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    }
55866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  }
55966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
56066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // We're done editting, reconstruct the archive.
56166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (TheArchive->writeToDisk(SymTable,TruncateNames,Compression,ErrMsg))
56266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    return true;
56366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (ReallyVerbose)
56466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    printSymbolTable();
56566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  return false;
56666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman}
56766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
56866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// doQuickAppend - Implements the 'q' operation. This function just
56966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// indiscriminantly adds the members to the archive and rebuilds it.
57066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool
57166b8ab22586debccb1f787d4d52b7f042d4ddeb8John BaumandoQuickAppend(std::string* ErrMsg) {
57266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Get the list of paths to append.
57366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (buildPaths(true, ErrMsg))
57466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    return true;
57566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (Paths.empty())
57666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    return false;
57766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
57866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Append them quickly.
57966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  for (std::set<sys::Path>::iterator PI = Paths.begin(), PE = Paths.end();
58066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman       PI != PE; ++PI) {
58166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    if (TheArchive->addFileBefore(*PI,TheArchive->end(),ErrMsg))
58266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      return true;
58366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  }
58466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
58566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // We're done editting, reconstruct the archive.
58666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (TheArchive->writeToDisk(SymTable,TruncateNames,Compression,ErrMsg))
58766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    return true;
58866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (ReallyVerbose)
58966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    printSymbolTable();
59066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  return false;
59166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman}
59266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
59366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// doReplaceOrInsert - Implements the 'r' operation. This function will replace
59466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// any existing files or insert new ones into the archive.
59566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanbool
59666b8ab22586debccb1f787d4d52b7f042d4ddeb8John BaumandoReplaceOrInsert(std::string* ErrMsg) {
59766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
59866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Build the list of files to be added/replaced.
59966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (buildPaths(true, ErrMsg))
60066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    return true;
60166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (Paths.empty())
60266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    return false;
60366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
60466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Keep track of the paths that remain to be inserted.
60566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  std::set<sys::Path> remaining(Paths);
60666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
60766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Default the insertion spot to the end of the archive
60866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  Archive::iterator insert_spot = TheArchive->end();
60966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
61066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Iterate over the archive contents
61166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
61266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman       I != E && !remaining.empty(); ++I ) {
61366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
61466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    // Determine if this archive member matches one of the paths we're trying
61566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    // to replace.
61666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
61766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    std::set<sys::Path>::iterator found = remaining.end();
61866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    for (std::set<sys::Path>::iterator RI = remaining.begin(),
61966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman         RE = remaining.end(); RI != RE; ++RI ) {
62066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      std::string compare(RI->str());
62166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (TruncateNames && compare.length() > 15) {
62266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        const char* nm = compare.c_str();
62366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        unsigned len = compare.length();
62466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        size_t slashpos = compare.rfind('/');
62566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        if (slashpos != std::string::npos) {
62666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          nm += slashpos + 1;
62766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          len -= slashpos +1;
62866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        }
62966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        if (len > 15)
63066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          len = 15;
63166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        compare.assign(nm,len);
63266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      }
63366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (compare == I->getPath().str()) {
63466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        found = RI;
63566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        break;
63666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      }
63766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    }
63866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
63966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    if (found != remaining.end()) {
64066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      std::string Err;
64166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      sys::PathWithStatus PwS(*found);
64266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      const sys::FileStatus *si = PwS.getFileStatus(false, &Err);
64366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (!si)
64466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        return true;
64566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (!si->isDir) {
64666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        if (OnlyUpdate) {
64766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          // Replace the item only if it is newer.
64866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          if (si->modTime > I->getModTime())
64966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman            if (I->replaceWith(*found, ErrMsg))
65066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman              return true;
65166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        } else {
65266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          // Replace the item regardless of time stamp
65366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman          if (I->replaceWith(*found, ErrMsg))
65466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman            return true;
65566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        }
65666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      } else {
65766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        // We purposefully ignore directories.
65866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      }
65966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
66066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      // Remove it from our "to do" list
66166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      remaining.erase(found);
66266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    }
66366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
66466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    // Determine if this is the place where we should insert
66566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    if ((AddBefore || InsertBefore) && RelPos == I->getPath().str())
66666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      insert_spot = I;
66766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    else if (AddAfter && RelPos == I->getPath().str()) {
66866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      insert_spot = I;
66966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      insert_spot++;
67066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    }
67166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  }
67266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
67366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // If we didn't replace all the members, some will remain and need to be
67466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // inserted at the previously computed insert-spot.
67566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (!remaining.empty()) {
67666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    for (std::set<sys::Path>::iterator PI = remaining.begin(),
67766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman         PE = remaining.end(); PI != PE; ++PI) {
67866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (TheArchive->addFileBefore(*PI,insert_spot, ErrMsg))
67966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        return true;
68066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    }
68166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  }
68266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
68366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // We're done editting, reconstruct the archive.
68466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (TheArchive->writeToDisk(SymTable,TruncateNames,Compression,ErrMsg))
68566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    return true;
68666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  if (ReallyVerbose)
68766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    printSymbolTable();
68866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  return false;
68966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman}
69066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
69166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman// main - main program for llvm-ar .. see comments in the code
69266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Baumanint main(int argc, char **argv) {
69366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Print a stack trace if we signal out.
69466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  sys::PrintStackTraceOnErrorSignal();
69566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  PrettyStackTraceProgram X(argc, argv);
69666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  LLVMContext &Context = getGlobalContext();
69766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
69866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
69966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Have the command line options parsed and handle things
70066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // like --help and --version.
70166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  cl::ParseCommandLineOptions(argc, argv,
70266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    "LLVM Archiver (llvm-ar)\n\n"
70366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    "  This program archives bitcode files into single libraries\n"
70466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  );
70566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
70666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  int exitCode = 0;
70766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
70866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Make sure we don't exit with "unhandled exception".
70966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  try {
71066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    // Do our own parsing of the command line because the CommandLine utility
71166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    // can't handle the grouped positional parameters without a dash.
71266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    ArchiveOperation Operation = parseCommandLine();
71366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
71466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    // Check the path name of the archive
71566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    sys::Path ArchivePath;
71666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    if (!ArchivePath.set(ArchiveName))
71766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      throw std::string("Archive name invalid: ") + ArchiveName;
71866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
71966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    // Create or open the archive object.
72066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    bool Exists;
72166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    if (llvm::sys::fs::exists(ArchivePath.str(), Exists) || !Exists) {
72266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      // Produce a warning if we should and we're creating the archive
72366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (!Create)
72466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        errs() << argv[0] << ": creating " << ArchivePath.str() << "\n";
72566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      TheArchive = Archive::CreateEmpty(ArchivePath, Context);
72666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      TheArchive->writeToDisk();
72766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    } else {
72866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      std::string Error;
72966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      TheArchive = Archive::OpenAndLoad(ArchivePath, Context, &Error);
73066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      if (TheArchive == 0) {
73166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        errs() << argv[0] << ": error loading '" << ArchivePath.str() << "': "
73266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman               << Error << "!\n";
73366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        return 1;
73466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      }
73566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    }
73666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
73766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    // Make sure we're not fooling ourselves.
73866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    assert(TheArchive && "Unable to instantiate the archive");
73966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
74066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    // Make sure we clean up the archive even on failure.
74166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    std::auto_ptr<Archive> AutoArchive(TheArchive);
74266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
74366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    // Perform the operation
74466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    std::string ErrMsg;
74566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    bool haveError = false;
74666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    switch (Operation) {
74766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      case Print:           haveError = doPrint(&ErrMsg); break;
74866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      case Delete:          haveError = doDelete(&ErrMsg); break;
74966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      case Move:            haveError = doMove(&ErrMsg); break;
75066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      case QuickAppend:     haveError = doQuickAppend(&ErrMsg); break;
75166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      case ReplaceOrInsert: haveError = doReplaceOrInsert(&ErrMsg); break;
75266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      case DisplayTable:    haveError = doDisplayTable(&ErrMsg); break;
75366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      case Extract:         haveError = doExtract(&ErrMsg); break;
75466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      case NoOperation:
75566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        errs() << argv[0] << ": No operation was selected.\n";
75666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman        break;
75766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    }
75866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    if (haveError) {
75966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      errs() << argv[0] << ": " << ErrMsg << "\n";
76066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman      return 1;
76166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    }
76266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  } catch (const char*msg) {
76366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    // These errors are usage errors, thrown only by the various checks in the
76466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    // code above.
76566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    errs() << argv[0] << ": " << msg << "\n\n";
76666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    cl::PrintHelpMessage();
76766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    exitCode = 1;
76866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  } catch (const std::string& msg) {
76966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    // These errors are thrown by LLVM libraries (e.g. lib System) and represent
77066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    // a more serious error so we bump the exitCode and don't print the usage.
77166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    errs() << argv[0] << ": " << msg << "\n";
77266b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    exitCode = 2;
77366b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  } catch (...) {
77466b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    // This really shouldn't happen, but just in case ....
77566b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    errs() << argv[0] << ": An unexpected unknown exception occurred.\n";
77666b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman    exitCode = 3;
77766b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  }
77866b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman
77966b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  // Return result code back to operating system.
78066b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman  return exitCode;
78166b8ab22586debccb1f787d4d52b7f042d4ddeb8John Bauman}
782