#include "uar.h" #pragma hdrstop #include "lib.h" #include "version.h" UARArchiveJob::UARArchiveJob() { dump_flags = 0; delete_source_objects = false; keep_archive_backups = true; nologo = false; } String UARArchiveJob::Usage() { return String().Cat() << NFormat("uar COFF librarian, version %d.%d.r%d, release date %`\n%s", UAR_VERSION_MAJOR, UAR_VERSION_MINOR, UAR_VERSION_RELEASE, UAR_DATE, UAR_COPYRIGHT) << "\n" "\n" "Currently supported MS lib-compatible options:\n" "\n" "-out: .. name of lib file to produce\n" "-list[:] .. dump library contents\n" "-nologo .. suppress startup banner (ignored)\n" "-machine:\n" "-verbose .. verbose link process report\n" " (handled as a neutral, not MS-specific option)\n" "\n" "Currently supported GNU ar-compatible options:\n" "\n" "-c .. don't complain when creating new archive\n" " (automatic, warnings shown in verbose mode only)\n" "-d .. remove files from archive\n" "-m .. move files to archive (delete original files)\n" "-p .. print archive contents\n" "-q .. quick append (same as -r in uar)\n" "-r .. replace & insert files in archive\n" "-s .. create archive index (ignored, automatic)\n" "-t .. type archive contents\n" "-x .. extract archive members\n" "\n" "uar-specific options:\n" "\n" "-dumpsym .. display archive symbol table\n" "-demangle .. display demangled symbol table\n" ; } void UARArchiveJob::ReadCommand(const char *cmd) { ReadCommand(SplitCmdArgs(cmd)); } void UARArchiveJob::ReadCommand(const Vector& cmdline) { for(int i = 0; i < cmdline.GetCount(); i++) { String arg = cmdline[i]; if(*arg == '-' || *arg == '/') { const char *ptr = ~arg + 1; const char *end = ptr; while(*end && *end != ':') end++; String cmd(ptr, end); String lcmd = ToLower(cmd); String val; if(*end == ':') val = end + 1; bool eaten = true; if(lcmd == "out" && !IsNull(val)) libraryfile = val; else if(lcmd == "list") { command = CMD_PRINT; printfile = val; } else if(lcmd == "nologo") nologo = true; else if(lcmd == "machine" && !IsNull(val)) { val = ToUpper(val); int m = COFFMachineCode(val); if(m == COFF_IMAGE_FILE_MACHINE_UNKNOWN) PutStdOut(NFormat("Unknown machine type: %s; supported machines are: %s", val, COFFMachineNames())); machine = m; } else eaten = false; if(eaten) armode = MODE_MSLIB; else { // if(lcmd == "dumpobj") // dump_flags |= DUMP_OBJECTS; if(lcmd == "dumpsym") dump_flags |= DUMP_SYMBOLS; else if(lcmd == "demangle") dump_flags |= DUMP_SYMBOLS | DUMP_SYMBOLS_DEMANGLED; else if(lcmd == "verbose") verbose = true; else { for(const char *p = ~arg + 1; *p;) switch(*p++) { case 'c': // don't complain when creating archive if(verbose) PutStdOut("option '-c' ignored (automatic)"); break; case 'd': // delete files command = CMD_REMOVE; break; case 'm': // move files command = CMD_ADD; delete_source_objects = true; break; case 'p': // print files command = CMD_PRINT; break; case 'q': // quick append command = CMD_ADD; break; case 'r': // replace & insert command = CMD_ADD; break; case 's': // create archive index if(verbose) PutStdOut("option '-s' ignored (automatic)"); break; case 't': // type contents command = CMD_CONTENTS; break; case 'x': // extract command = CMD_EXTRACT; throw Exc("option '-x' not supported (yet)"); default: throw Exc(NFormat("Invalid command line option: '%s'", arg)); } armode = MODE_GNUAR; } } } else if(IsNull(libraryfile)) libraryfile = AppendExt(arg, ".a"); else { String fn = AppendExt(arg, armode == MODE_GNUAR ? ".o" : ".obj"); if(command == CMD_ADD) LoadFile(fn); else object_names.Add(fn); } } } void UARArchiveJob::Build() { if(IsNull(libraryfile)) throw Exc("Archive file not specified."); archive_must_exist = (command != CMD_ADD && use_existing_archive); if(use_existing_archive) LoadLibrary(libraryfile); SortGlobals(); if(dump_flags & DUMP_SYMBOLS) { PutStdOut(NFormat("%d symbol(s) in %d object file(s)", symbol_names.GetCount(), objects.GetCount())); PutStdOut("Object Symbol"); for(int i = 0; i < symbol_names.GetCount(); i++) { String symname = symbol_names[i]; if(dump_flags & DUMP_SYMBOLS_DEMANGLED) symname = DemangleName(symname, armode == MODE_MSLIB ? MANGLING_MSC : MANGLING_GCC); PutStdOut(NFormat("%15= 0) objects.Remove(t); else PutStdOut(NFormat("%s: not found in archive (trimmed name = %s)", object_names[i], n)); } } void UARArchiveJob::Extract() { for(int i = 0; i < object_names.GetCount(); i++) { String fn = object_names[i], n = TrimObjectName(fn); int t = FindFieldIndex(objects, &Object::trimmed_name, n); if(t >= 0) { if(!SaveFile(fn, objects[t].object_data)) throw Exc(NFormat("%s: error writing extracted file (trimmed name = %s)", fn, n)); if(verbose) PutStdOut(NFormat("%s: extracted member %s (%d B)", fn, n, objects[t].object_data.GetLength())); } else PutStdOut(NFormat("%s: not found in archive (trimmed name = %s)", fn, n)); } } void UARArchiveJob::Print() { PutStdOut("Offset Size Time Object"); for(int i = 0; i < objects.GetCount(); i++) { const Object& o = objects[i]; PutStdOut(NFormat("%10>d %10>d %12>0n %s", o.header_offset, o.object_data.GetLength(), o.filetime, o.filename)); if(command == CMD_PRINT) for(int s = 0; s < symbol_names.GetCount(); s++) if(symbol_objects[s] == i) PutStdOut("\t" + symbol_names[s]); } }