#include <mach/mach.h>
#include "stuff/openstep_mach.h"
#include <libc.h>
#ifndef __OPENSTEP__
#include <utime.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <ar.h>
#include <mach-o/ranlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "stuff/bool.h"
#include "stuff/ofile.h"
#include "stuff/round.h"
#include "stuff/errors.h"
#include "stuff/allocate.h"
#include "stuff/execute.h"
#include "stuff/version_number.h"
#include "make.h"
#include <mach/mach_init.h>
#if defined(__OPENSTEP__) || defined(__GONZO_BUNSEN_BEAKER__)
#include <servers/netname.h>
#else
#include <servers/bootstrap.h>
#endif
char *progname = NULL;
static enum byte_sex host_byte_sex = UNKNOWN_BYTE_SEX;
static long toc_time = 0;
static u_short toc_mode = 0;
struct cmd_flags {
char **files;
unsigned long
nfiles;
char **filelist;
enum bool
no_files_ok;
enum bool ranlib;
enum bool s;
enum bool a;
enum bool c;
enum bool t;
enum bool f;
char *output;
enum bool final_output_specified;
enum bool dynamic;
char *compatibility;
char *current;
char *install_name;
char *seg1addr;
char *segs_read_only_addr;
char *segs_read_write_addr;
char *seg_addr_table;
char *seg_addr_table_filename;
char **Ldirs;
unsigned long
nLdirs;
char **ldflags;
unsigned long
nldflags;
enum bool verbose;
struct arch_flag
arch_only_flag;
enum bool
prebinding_flag_specified;
enum bool
prebinding;
enum bool
all_load_flag_specified;
enum bool
all_load;
enum bool
use_long_names;
enum bool L_or_T_specified;
enum bool
rc_trace_archives;
enum bool
search_paths_first;
};
static struct cmd_flags cmd_flags = { 0 };
static char *next_root = NULL;
char *standard_dirs[] = {
"/lib/",
"/usr/lib/",
"/usr/local/lib/",
NULL
};
static struct arch *archs = NULL;
static unsigned long narchs = 0;
struct arch {
struct arch_flag arch_flag;
unsigned long size;
unsigned long toc_size;
struct ar_hdr toc_ar_hdr;
enum bool toc_long_name;
char *toc_name;
unsigned long toc_name_size;
struct ranlib *toc_ranlibs;
unsigned long toc_nranlibs;
char *toc_strings;
unsigned long toc_strsize;
struct member *members;
unsigned long nmembers;
};
struct member {
unsigned long offset;
struct ar_hdr ar_hdr;
char null_byte;
char *object_addr;
unsigned long object_size;
enum byte_sex object_byte_sex;
struct mach_header *mh;
struct load_command
*load_commands;
struct symtab_command *st;
struct section **sections;
char *member_name;
unsigned long member_name_size;
enum bool output_long_name;
char *input_file_name;
char *input_base_name;
unsigned long input_base_name_size;
struct ar_hdr *input_ar_hdr;
};
static void usage(
void);
static void process(
void);
static char *file_name_from_l_flag(
char *l_flag);
static char *search_for_file(
char *base_name);
static char * search_paths_for_lname(
const char *lname_argument);
static char * search_path_for_lname(
const char *dir,
const char *lname_argument);
static void add_member(
struct ofile *ofile);
static void free_archs(
void);
static void create_library(
char *output);
static void create_dynamic_shared_library(
char *output);
static void create_dynamic_shared_library_cleanup(
int sig);
static void make_table_of_contents(
struct arch *arch,
char *output);
static int ranlib_name_qsort(
const struct ranlib *ran1,
const struct ranlib *ran2);
static int ranlib_offset_qsort(
const struct ranlib *ran1,
const struct ranlib *ran2);
static enum bool toc_symbol(
struct nlist *symbol,
struct section **sections);
static enum bool check_sort_ranlibs(
struct arch *arch,
char *output);
static void warn_duplicate_member_names(
void);
static int member_name_qsort(
const struct member *member1,
const struct member *member2);
static int member_offset_qsort(
const struct member *member1,
const struct member *member2);
static void warn_member(
struct arch *arch,
struct member *member,
const char *format, ...) __attribute__ ((format (printf, 3, 4)));
int
main(
int argc,
char **argv,
char **envp)
{
char *p, *endp, *filelist, *dirname, *addr;
int fd, i;
struct stat stat_buf;
unsigned long j, temp, nfiles, maxfiles;
int oumask, numask;
kern_return_t r;
enum bool lflags_seen, bad_flag_seen;
lflags_seen = FALSE;
progname = argv[0];
host_byte_sex = get_host_byte_sex();
toc_time = time(0);
numask = 0;
oumask = umask(numask);
toc_mode = S_IFREG | (0666 & ~oumask);
(void)umask(oumask);
p = strrchr(argv[0], '/');
if(p != NULL)
p++;
else
p = argv[0];
if(strncmp(p, "ranlib", sizeof("ranlib") - 1) == 0)
cmd_flags.ranlib = TRUE;
cmd_flags.use_long_names = TRUE;
maxfiles = argc;
cmd_flags.files = allocate(sizeof(char *) * maxfiles);
cmd_flags.filelist = allocate(sizeof(char *) * maxfiles);
memset(cmd_flags.filelist, '\0', sizeof(char *) * maxfiles);
for(i = 1; i < argc; i++){
if(argv[i][0] == '-'){
if(argv[i][1] == '\0'){
for(i += 1 ; i < argc; i++)
cmd_flags.files[cmd_flags.nfiles++] = argv[i];
break;
}
if(strcmp(argv[i], "-o") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(i + 1 == argc){
error("missing argument to: %s option", argv[i]);
usage();
}
if(cmd_flags.output != NULL){
error("more than one: %s option specified", argv[i]);
usage();
}
cmd_flags.output = argv[i+1];
i++;
}
else if(strcmp(argv[i], "-arch_only") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(i + 1 == argc){
error("missing argument to %s option", argv[i]);
usage();
}
if(cmd_flags.arch_only_flag.name != NULL){
error("more than one: %s option specified", argv[i]);
usage();
}
else{
if(get_arch_from_flag(argv[i+1],
&cmd_flags.arch_only_flag) == 0){
error("unknown architecture specification flag: "
"%s %s", argv[i], argv[i+1]);
arch_usage();
usage();
}
}
i++;
}
else if(strcmp(argv[i], "-dynamic") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
cmd_flags.dynamic = TRUE;
}
else if(strcmp(argv[i], "-static") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
cmd_flags.dynamic = FALSE;
}
else if(strcmp(argv[i], "-filelist") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(i + 1 == argc){
error("missing argument to: %s option", argv[i]);
usage();
}
filelist = argv[i + 1];
dirname = strrchr(filelist, ',');
if(dirname != NULL){
*dirname = '\0';
dirname++;
}
else
dirname = "";
if((fd = open(filelist, O_RDONLY, 0)) == -1)
system_fatal("can't open file list file: %s", filelist);
if(fstat(fd, &stat_buf) == -1)
system_fatal("can't stat file list file: %s", filelist);
if(stat_buf.st_size != 0){
if((r = map_fd((int)fd, (vm_offset_t)0,
(vm_offset_t *)&(addr), (boolean_t)TRUE,
(vm_size_t)stat_buf.st_size)) != KERN_SUCCESS)
mach_fatal(r, "can't map file list file: %s",
filelist);
}
else{
fatal("file list file: %s is empty", filelist);
}
if(*dirname != '\0')
dirname[-1] = ',';
close(fd);
nfiles = 0;
for(j = 0; j < stat_buf.st_size; j++){
if(addr[j] == '\n')
nfiles++;
}
if(addr[stat_buf.st_size - 1] != '\n')
nfiles++;
p = allocate((strlen(dirname) + 1) * nfiles +
stat_buf.st_size);
cmd_flags.files = reallocate(cmd_flags.files,
sizeof(char *) * (maxfiles + nfiles));
cmd_flags.filelist = reallocate(cmd_flags.filelist,
sizeof(char *) * (maxfiles + nfiles));
memset(cmd_flags.filelist + maxfiles, '\0',
sizeof(char *) * nfiles);
maxfiles += nfiles;
cmd_flags.files[cmd_flags.nfiles] = p;
cmd_flags.filelist[cmd_flags.nfiles] = filelist;
cmd_flags.nfiles++;
if(*dirname != '\0'){
strcpy(p, dirname);
p += strlen(dirname);
*p++ = '/';
}
for(j = 0; j < stat_buf.st_size; j++){
if(addr[j] != '\n')
*p++ = addr[j];
else{
*p++ = '\0';
if(j != stat_buf.st_size - 1){
cmd_flags.files[cmd_flags.nfiles] = p;
cmd_flags.filelist[cmd_flags.nfiles] =argv[i+1];
cmd_flags.nfiles++;
if(*dirname != '\0'){
strcpy(p, dirname);
p += strlen(dirname);
*p++ = '/';
}
}
}
}
if(addr[stat_buf.st_size - 1] != '\n')
*p = '\0';
i++;
}
else if(strcmp(argv[i], "-compatibility_version") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(i + 1 == argc){
error("missing argument to: %s option", argv[i]);
usage();
}
if(cmd_flags.compatibility != NULL){
error("more than one: %s option specified", argv[i]);
usage();
}
if(get_version_number(argv[i], argv[i+1], &temp) == FALSE){
usage();
}
cmd_flags.compatibility = argv[i+1];
i++;
}
else if(strcmp(argv[i], "-current_version") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(i + 1 == argc){
error("missing argument to: %s option", argv[i]);
usage();
}
if(cmd_flags.current != NULL){
error("more than one: %s option specified", argv[i]);
usage();
}
if(get_version_number(argv[i], argv[i+1], &temp) == FALSE){
usage();
}
cmd_flags.current = argv[i+1];
i++;
}
else if(strcmp(argv[i], "-install_name") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(i + 1 == argc){
error("missing argument to: %s option", argv[i]);
usage();
}
if(cmd_flags.install_name != NULL){
error("more than one: %s option specified", argv[i]);
usage();
}
cmd_flags.install_name = argv[i+1];
i++;
}
else if(strcmp(argv[i], "-seg1addr") == 0 ||
strcmp(argv[i], "-image_base") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(i + 1 == argc){
error("missing argument to: %s option", argv[i]);
usage();
}
if(cmd_flags.seg1addr != NULL){
error("more than one: %s option specified", argv[i]);
usage();
}
temp = strtoul(argv[i + 1], &endp, 16);
if(*endp != '\0'){
error("address for -seg1addr %s not a proper "
"hexadecimal number", argv[i+1]);
usage();
}
cmd_flags.seg1addr = argv[i+1];
i++;
}
else if(strcmp(argv[i], "-segs_read_only_addr") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(i + 1 == argc){
error("missing argument to: %s option", argv[i]);
usage();
}
if(cmd_flags.segs_read_only_addr != NULL){
error("more than one: %s option specified", argv[i]);
usage();
}
temp = strtoul(argv[i + 1], &endp, 16);
if(*endp != '\0'){
error("address for -segs_read_only_addr %s not a "
"proper hexadecimal number", argv[i+1]);
usage();
}
cmd_flags.segs_read_only_addr = argv[i+1];
i++;
}
else if(strcmp(argv[i], "-segs_read_write_addr") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(i + 1 == argc){
error("missing argument to: %s option", argv[i]);
usage();
}
if(cmd_flags.segs_read_write_addr != NULL){
error("more than one: %s option specified", argv[i]);
usage();
}
temp = strtoul(argv[i + 1], &endp, 16);
if(*endp != '\0'){
error("address for -segs_read_write_addr %s not a "
"proper hexadecimal number", argv[i+1]);
usage();
}
cmd_flags.segs_read_write_addr = argv[i+1];
i++;
}
else if(strcmp(argv[i], "-seg_addr_table") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(i + 1 == argc){
error("missing argument to: %s option", argv[i]);
usage();
}
if(cmd_flags.seg_addr_table != NULL){
error("more than one: %s option specified", argv[i]);
usage();
}
cmd_flags.seg_addr_table = argv[i+1];
i++;
}
else if(strcmp(argv[i], "-seg_addr_table_filename") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(i + 1 == argc){
error("missing argument to: %s option", argv[i]);
usage();
}
if(cmd_flags.seg_addr_table_filename != NULL){
error("more than one: %s option specified", argv[i]);
usage();
}
cmd_flags.seg_addr_table_filename = argv[i+1];
i++;
}
else if(strcmp(argv[i], "-sectcreate") == 0 ||
strcmp(argv[i], "-segcreate") == 0 ||
strcmp(argv[i], "-sectorder") == 0 ||
strcmp(argv[i], "-sectalign") == 0 ||
strcmp(argv[i], "-segprot") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(i + 3 >= argc){
error("not enough arguments follow %s", argv[i]);
usage();
}
cmd_flags.ldflags = reallocate(cmd_flags.ldflags,
sizeof(char *) * (cmd_flags.nldflags + 4));
cmd_flags.ldflags[cmd_flags.nldflags++] = argv[i];
cmd_flags.ldflags[cmd_flags.nldflags++] = argv[i+1];
cmd_flags.ldflags[cmd_flags.nldflags++] = argv[i+2];
cmd_flags.ldflags[cmd_flags.nldflags++] = argv[i+3];
if(strcmp(argv[i], "-sectcreate") == 0 ||
strcmp(argv[i], "-segcreate") == 0)
cmd_flags.no_files_ok = TRUE;
i += 3;
}
else if(strcmp(argv[i], "-segalign") == 0 ||
strcmp(argv[i], "-undefined") == 0 ||
strcmp(argv[i], "-multiply_defined") == 0 ||
strcmp(argv[i], "-multiply_defined_unused") == 0 ||
strcmp(argv[i], "-umbrella") == 0 ||
strcmp(argv[i], "-sub_umbrella") == 0 ||
strcmp(argv[i], "-sub_library") == 0 ||
strcmp(argv[i], "-allowable_client") == 0 ||
strcmp(argv[i], "-read_only_relocs") == 0 ||
strcmp(argv[i], "-init") == 0 ||
strcmp(argv[i], "-U") == 0 ||
strcmp(argv[i], "-Y") == 0 ||
strcmp(argv[i], "-dylib_file") == 0 ||
strcmp(argv[i], "-final_output") == 0 ||
strcmp(argv[i], "-headerpad") == 0 ||
strcmp(argv[i], "-weak_reference_mismatches") == 0 ||
strcmp(argv[i], "-u") == 0 ||
strcmp(argv[i], "-exported_symbols_list") == 0 ||
strcmp(argv[i], "-unexported_symbols_list") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(i + 1 >= argc){
error("not enough arguments follow %s", argv[i]);
usage();
}
cmd_flags.ldflags = reallocate(cmd_flags.ldflags,
sizeof(char *) * (cmd_flags.nldflags + 2));
cmd_flags.ldflags[cmd_flags.nldflags++] = argv[i];
cmd_flags.ldflags[cmd_flags.nldflags++] = argv[i+1];
if(strcmp(argv[i], "-final_output") == 0)
cmd_flags.final_output_specified = TRUE;
i += 1;
}
else if(strcmp(argv[i], "-sectorder_detail") == 0 ||
strcmp(argv[i], "-Sn") == 0 ||
strcmp(argv[i], "-Si") == 0 ||
strcmp(argv[i], "-S") == 0 ||
strcmp(argv[i], "-X") == 0 ||
strcmp(argv[i], "-x") == 0 ||
strcmp(argv[i], "-whatsloaded") == 0 ||
strcmp(argv[i], "-whyload") == 0 ||
strcmp(argv[i], "-arch_errors_fatal") == 0 ||
strcmp(argv[i], "-run_init_lazily") == 0 ||
strcmp(argv[i], "-twolevel_namespace") == 0 ||
strcmp(argv[i], "-twolevel_namespace_hints") == 0 ||
strcmp(argv[i], "-flat_namespace") == 0 ||
strcmp(argv[i], "-nomultidefs") == 0 ||
strcmp(argv[i], "-headerpad_max_install_names") == 0 ||
strcmp(argv[i], "-prebind_all_twolevel_modules") == 0 ||
strcmp(argv[i], "-ObjC") == 0 ||
strcmp(argv[i], "-M") == 0 ||
strcmp(argv[i], "-single_module") == 0 ||
strcmp(argv[i], "-multi_module") == 0 ||
strcmp(argv[i], "-m") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
cmd_flags.ldflags = reallocate(cmd_flags.ldflags,
sizeof(char *) * (cmd_flags.nldflags + 1));
cmd_flags.ldflags[cmd_flags.nldflags++] = argv[i];
}
else if(strcmp(argv[i], "-no_arch_warnings") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
}
else if(strcmp(argv[i], "-prebind") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(cmd_flags.prebinding_flag_specified == TRUE &&
cmd_flags.prebinding == FALSE){
error("both -prebind and -noprebind can't be "
"specified");
usage();
}
cmd_flags.prebinding_flag_specified = TRUE;
cmd_flags.prebinding = TRUE;
cmd_flags.ldflags = reallocate(cmd_flags.ldflags,
sizeof(char *) * (cmd_flags.nldflags + 1));
cmd_flags.ldflags[cmd_flags.nldflags++] = argv[i];
}
else if(strcmp(argv[i], "-noprebind") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(cmd_flags.prebinding_flag_specified == TRUE &&
cmd_flags.prebinding == TRUE){
error("both -prebind and -noprebind can't be "
"specified");
usage();
}
cmd_flags.prebinding_flag_specified = TRUE;
cmd_flags.prebinding = FALSE;
cmd_flags.ldflags = reallocate(cmd_flags.ldflags,
sizeof(char *) * (cmd_flags.nldflags + 1));
cmd_flags.ldflags[cmd_flags.nldflags++] = argv[i];
}
else if(strcmp(argv[i], "-all_load") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(cmd_flags.all_load_flag_specified == TRUE &&
cmd_flags.all_load == FALSE){
error("both -all_load and -noall_load can't be "
"specified");
usage();
}
cmd_flags.all_load_flag_specified = TRUE;
cmd_flags.all_load = TRUE;
}
else if(strcmp(argv[i], "-noall_load") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(cmd_flags.all_load_flag_specified == TRUE &&
cmd_flags.all_load == TRUE){
error("both -all_load and -noall_load can't be "
"specified");
usage();
}
cmd_flags.all_load_flag_specified = TRUE;
cmd_flags.all_load = FALSE;
}
else if(strncmp(argv[i], "-y", 2) == 0 ||
strncmp(argv[i], "-i", 2) == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(strncmp(argv[i], "-i", 2) == 0)
cmd_flags.no_files_ok = TRUE;
cmd_flags.ldflags = reallocate(cmd_flags.ldflags,
sizeof(char *) * (cmd_flags.nldflags + 1));
cmd_flags.ldflags[cmd_flags.nldflags++] = argv[i];
}
else if(argv[i][1] == 'l'){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(argv[i][2] == '\0'){
error("-l: name missing");
usage();
}
cmd_flags.files[cmd_flags.nfiles++] = argv[i];
lflags_seen = TRUE;
}
else if(strncmp(argv[i], "-weak-l", 7) == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(argv[i][7] == '\0'){
error("-weak-l: name missing");
usage();
}
cmd_flags.files[cmd_flags.nfiles++] = argv[i];
lflags_seen = TRUE;
}
else if(strcmp(argv[i], "-framework") == 0 ||
strcmp(argv[i], "-weak_framework") == 0 ||
strcmp(argv[i], "-weak_library") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
if(i + 1 >= argc){
error("not enough arguments follow %s", argv[i]);
usage();
}
cmd_flags.files[cmd_flags.nfiles++] = argv[i];
cmd_flags.files[cmd_flags.nfiles++] = argv[i+1];
lflags_seen = TRUE;
i += 1;
}
else if(strcmp(argv[i], "-T") == 0){
if(cmd_flags.L_or_T_specified == TRUE){
error("both -T and -L can't be specified");
usage();
}
cmd_flags.L_or_T_specified = TRUE;
cmd_flags.use_long_names = FALSE;
}
else if(argv[i][1] == 'L' || argv[i][1] == 'F'){
if(argv[i][1] == 'L' && argv[i][2] == '\0'){
if(cmd_flags.L_or_T_specified == TRUE){
error("both -T and -L can't be specified");
usage();
}
cmd_flags.L_or_T_specified = TRUE;
cmd_flags.use_long_names = TRUE;
}
else{
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
cmd_flags.Ldirs = realloc(cmd_flags.Ldirs,
sizeof(char *) * (cmd_flags.nLdirs + 1));
cmd_flags.Ldirs[cmd_flags.nLdirs++] = argv[i];
}
}
else if(argv[i][1] == 'g'){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
;
}
else if(strcmp(argv[i], "-pg") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
;
}
else if(strcmp(argv[i], "-search_paths_first") == 0){
if(cmd_flags.ranlib == TRUE){
error("unknown option: %s", argv[i]);
usage();
}
cmd_flags.search_paths_first = TRUE;
cmd_flags.ldflags = reallocate(cmd_flags.ldflags,
sizeof(char *) * (cmd_flags.nldflags + 1));
cmd_flags.ldflags[cmd_flags.nldflags++] = argv[i];
}
else{
for(j = 1; argv[i][j] != '\0'; j++){
switch(argv[i][j]){
case 's':
cmd_flags.s = TRUE;
break;
case 'a':
cmd_flags.a = TRUE;
break;
case 'c':
cmd_flags.c = TRUE;
break;
case 'v':
if(cmd_flags.ranlib == TRUE){
error("unknown option character `%c' in: %s",
argv[i][j], argv[i]);
usage();
}
cmd_flags.verbose= TRUE;
break;
case 't':
if(cmd_flags.ranlib == TRUE){
warning("touch option (`%c' in: %s) ignored "
"(table of contents rebuilt anyway)",
argv[i][j], argv[i]);
cmd_flags.t = TRUE;
break;
}
else {
error("unknown option character `%c' in: %s",
argv[i][j], argv[i]);
usage();
}
case 'f':
if(cmd_flags.ranlib == TRUE){
cmd_flags.f = TRUE;
break;
}
else {
error("unknown option character `%c' in: %s",
argv[i][j], argv[i]);
usage();
}
default:
error("unknown option character `%c' in: %s",
argv[i][j], argv[i]);
usage();
}
}
}
}
else
cmd_flags.files[cmd_flags.nfiles++] = argv[i];
}
if(getenv("RC_TRACE_ARCHIVES") != NULL)
cmd_flags.rc_trace_archives = TRUE;
next_root = getenv("NEXT_ROOT");
if(next_root != NULL){
for(i = 0; standard_dirs[i] != NULL; i++){
p = allocate(strlen(next_root) +
strlen(standard_dirs[i]) + 1);
strcpy(p, next_root);
strcat(p, standard_dirs[i]);
standard_dirs[i] = p;
}
}
if(cmd_flags.ranlib == FALSE && cmd_flags.dynamic == TRUE){
if(cmd_flags.s == TRUE){
warning("-static not specified, -s invalid");
}
if(cmd_flags.a == TRUE){
warning("-static not specified, -a invalid");
}
if(cmd_flags.c == TRUE){
warning("-static not specified, -c invalid");
}
if(cmd_flags.L_or_T_specified == TRUE){
if(cmd_flags.use_long_names == TRUE)
warning("-static not specified, -L invalid");
else
warning("-static not specified, -T invalid");
}
}
if(cmd_flags.s == TRUE && cmd_flags.a == TRUE){
error("only one of -s or -a can be specified");
usage();
}
if(cmd_flags.ranlib == FALSE && cmd_flags.output == NULL){
error("no output file specified (specify with -o output)");
usage();
}
if(cmd_flags.dynamic == FALSE){
if(cmd_flags.compatibility != NULL){
warning("-dynamic not specified, -compatibility_version %s "
"invalid", cmd_flags.compatibility);
}
if(cmd_flags.current != NULL){
warning("-dynamic not specified, -current_version %s invalid",
cmd_flags.current);
}
if(cmd_flags.install_name != NULL){
warning("-dynamic not specified, -install_name %s invalid",
cmd_flags.install_name);
}
if(cmd_flags.seg1addr != NULL){
warning("-dynamic not specified, -seg1addr %s invalid",
cmd_flags.seg1addr);
}
if(cmd_flags.segs_read_only_addr != NULL){
warning("-dynamic not specified, -segs_read_only_addr %s "
"invalid", cmd_flags.segs_read_only_addr);
}
if(cmd_flags.segs_read_write_addr != NULL){
warning("-dynamic not specified, -segs_read_write_addr %s "
"invalid", cmd_flags.segs_read_write_addr);
}
if(cmd_flags.seg_addr_table != NULL){
warning("-dynamic not specified, -seg_addr_table %s "
"invalid", cmd_flags.seg_addr_table);
}
if(cmd_flags.seg_addr_table_filename != NULL){
warning("-dynamic not specified, -seg_addr_table_filename %s "
"invalid", cmd_flags.seg_addr_table_filename);
}
if(cmd_flags.all_load_flag_specified == TRUE){
if(cmd_flags.all_load == TRUE)
warning("-dynamic not specified, -all_load invalid");
else
warning("-dynamic not specified, -noall_load invalid");
}
if(cmd_flags.nldflags != 0){
fprintf(stderr, "%s: -dynamic not specified the following "
"flags are invalid: ", progname);
for(j = 0; j < cmd_flags.nldflags; j++)
fprintf(stderr, "%s ", cmd_flags.ldflags[j]);
fprintf(stderr, "\n");
}
if(cmd_flags.nLdirs != 0){
bad_flag_seen = FALSE;
for(j = 0; j < cmd_flags.nLdirs; j++){
if(strncmp(cmd_flags.Ldirs[j], "-L", 2) == 0)
continue;
if(bad_flag_seen == FALSE){
fprintf(stderr, "%s: -dynamic not specified the "
"following flags are invalid: ", progname);
bad_flag_seen = TRUE;
}
fprintf(stderr, "%s ", cmd_flags.Ldirs[j]);
}
if(bad_flag_seen == TRUE)
fprintf(stderr, "\n");
}
}
else{
if(getenv("LD_PREBIND") != NULL){
if(cmd_flags.prebinding_flag_specified == TRUE &&
cmd_flags.prebinding == FALSE){
warning("LD_PREBIND environment variable ignored because "
"-noprebind specified");
}
else{
cmd_flags.prebinding_flag_specified = TRUE;
cmd_flags.prebinding = TRUE;
}
}
}
if(cmd_flags.nfiles == 0){
if(cmd_flags.ranlib == TRUE){
error("no archives specified");
usage();
}
else{
if(cmd_flags.dynamic == TRUE && cmd_flags.no_files_ok == TRUE)
warning("warning no files specified");
else{
error("no files specified");
usage();
}
}
}
if(cmd_flags.a == FALSE)
cmd_flags.s = TRUE;
process();
if(errors == 0)
return(EXIT_SUCCESS);
else
return(EXIT_FAILURE);
}
static
void
usage(
void)
{
if(cmd_flags.ranlib)
fprintf(stderr, "Usage: %s [-sactfLT] [-] archive [...]\n",
progname);
else{
fprintf(stderr, "Usage: %s -static [-] file [...] "
"[-filelist listfile[,dirname]] [-arch_only arch] "
"[-sacLT]\n", progname);
fprintf(stderr, "Usage: %s -dynamic [-] file [...] "
"[-filelist listfile[,dirname]] [-arch_only arch] "
"[-o output] [-install_name name] "
"[-compatibility_version #] [-current_version #] "
"[-seg1addr 0x#] [-segs_read_only_addr 0x#] "
"[-segs_read_write_addr 0x#] [-seg_addr_table <filename>] "
"[-seg_addr_table_filename <file_system_path>] "
"[-all_load] [-noall_load]\n",
progname);
}
exit(EXIT_FAILURE);
}
static
void
process(
void)
{
unsigned long i, j, k, previous_errors;
struct ofile *ofiles;
char *file_name;
enum bool flag, rc_trace_archive_printed;
ofiles = allocate(sizeof(struct ofile) * cmd_flags.nfiles);
for(i = 0; i < cmd_flags.nfiles; i++){
if(strncmp(cmd_flags.files[i], "-l", 2) == 0 ||
strncmp(cmd_flags.files[i], "-weak-l", 7) == 0){
file_name = file_name_from_l_flag(cmd_flags.files[i]);
if(file_name != NULL)
if(ofile_map(file_name, NULL, NULL, ofiles + i, TRUE) ==
FALSE)
continue;
}
else if(strcmp(cmd_flags.files[i], "-framework") == 0 ||
strcmp(cmd_flags.files[i], "-weak_framework") == 0 ||
strcmp(cmd_flags.files[i], "-weak_library") == 0){
i++;
continue;
}
else{
if(ofile_map(cmd_flags.files[i], NULL, NULL, ofiles + i,
TRUE) == FALSE)
continue;
}
previous_errors = errors;
errors = 0;
rc_trace_archive_printed = FALSE;
if(ofiles[i].file_type == OFILE_FAT){
(void)ofile_first_arch(ofiles + i);
do{
if(ofiles[i].arch_type == OFILE_ARCHIVE){
if(cmd_flags.rc_trace_archives == TRUE &&
cmd_flags.dynamic == FALSE &&
rc_trace_archive_printed == FALSE){
printf("[Logging for Build & Integration] Used "
"static archive: %s\n", ofiles[i].file_name);
rc_trace_archive_printed = TRUE;
}
if((flag = ofile_first_member(ofiles + i)) == TRUE){
if(ofiles[i].member_ar_hdr != NULL &&
strncmp(ofiles[i].member_name, SYMDEF,
sizeof(SYMDEF) - 1) == 0)
flag = ofile_next_member(ofiles + i);
while(flag == TRUE){
if(ofiles[i].mh != NULL ||
cmd_flags.ranlib == TRUE)
add_member(ofiles + i);
else{
error("for architecture: %s file: %s(%.*s) "
"is not an object file (not allowed "
"in a library)",
ofiles[i].arch_flag.name,
cmd_flags.files[i],
(int)ofiles[i].member_name_size,
ofiles[i].member_name);
}
flag = ofile_next_member(ofiles + i);
}
}
}
else if(ofiles[i].arch_type == OFILE_Mach_O){
if(cmd_flags.ranlib == TRUE){
error("for architecture: %s file: %s is not an "
"archive (no processing done on this file)",
ofiles[i].arch_flag.name, cmd_flags.files[i]);
goto ranlib_fat_error;
}
else
add_member(ofiles + i);
}
else if(ofiles[i].arch_type == OFILE_UNKNOWN){
if(cmd_flags.ranlib == TRUE){
error("for architecture: %s file: %s is not an "
"archive (no processing done on this file)",
ofiles[i].arch_flag.name, cmd_flags.files[i]);
goto ranlib_fat_error;
}
else{
error("for architecture: %s file: %s is not an "
"object file (not allowed in a library)",
ofiles[i].arch_flag.name, cmd_flags.files[i]);
}
}
}while(ofile_next_arch(ofiles + i) == TRUE);
}
else if(ofiles[i].file_type == OFILE_ARCHIVE){
if(cmd_flags.rc_trace_archives == TRUE &&
cmd_flags.dynamic == FALSE &&
rc_trace_archive_printed == FALSE){
printf("[Logging for Build & Integration] Used static "
"archive: %s\n", ofiles[i].file_name);
rc_trace_archive_printed = TRUE;
}
if((flag = ofile_first_member(ofiles + i)) == TRUE){
if(ofiles[i].member_ar_hdr != NULL &&
strncmp(ofiles[i].member_name, SYMDEF,
sizeof(SYMDEF) - 1) == 0)
flag = ofile_next_member(ofiles + i);
while(flag == TRUE){
if(ofiles[i].member_type == OFILE_FAT){
(void)ofile_first_arch(ofiles + i);
do{
if(ofiles[i].mh != NULL ||
cmd_flags.ranlib == TRUE){
add_member(ofiles + i);
}
else{
error("file: %s(%.*s) for architecture: %s "
"is not an object file (not allowed in "
"a library)", cmd_flags.files[i],
(int)ofiles[i].member_name_size,
ofiles[i].member_name,
ofiles[i].arch_flag.name);
}
}while(ofile_next_arch(ofiles + i) == TRUE);
}
else if(ofiles[i].mh != NULL ||
cmd_flags.ranlib == TRUE){
add_member(ofiles + i);
}
else{
error("file: %s(%.*s) is not an object file (not "
"allowed in a library)", cmd_flags.files[i],
(int)ofiles[i].member_name_size,
ofiles[i].member_name);
}
flag = ofile_next_member(ofiles + i);
}
}
}
else if(ofiles[i].file_type == OFILE_Mach_O){
if(cmd_flags.ranlib == TRUE){
error("file: %s is not an archive", cmd_flags.files[i]);
continue;
}
add_member(ofiles + i);
}
else{
if(cmd_flags.ranlib == TRUE){
error("file: %s is not an archive", cmd_flags.files[i]);
continue;
}
else{
error("file: %s is not an object file (not allowed in a "
"library)", cmd_flags.files[i]);
}
}
if(cmd_flags.ranlib == TRUE){
if(narchs > 1){
for(j = 0; j < narchs; j++){
for(k = 0; k < archs[j].nmembers; k++){
if(archs[j].members[k].mh == NULL){
error("library member: %s(%.*s) is not an "
"object file (not allowed in a library "
"with multiple architectures)",
cmd_flags.files[i],
(int)archs[j].members[k].
input_base_name_size,
archs[j].members[k].input_base_name);
}
}
}
}
if(errors == 0)
create_library(cmd_flags.files[i]);
if(cmd_flags.nfiles > 1){
ranlib_fat_error:
free_archs();
ofile_unmap(ofiles + i);
}
}
errors += previous_errors;
}
if(cmd_flags.ranlib == FALSE && errors == 0)
create_library(cmd_flags.output);
}
static
char *
file_name_from_l_flag(
char *l_flag)
{
char *file_name, *p, *start;
if(strncmp(l_flag, "-weak-l", 7) == 0)
start = &l_flag[7];
else
start = &l_flag[2];
p = strrchr(start, '.');
if(p != NULL && strcmp(p, ".o") == 0){
p = start;
file_name = search_for_file(p);
}
else{
file_name = NULL;
if(cmd_flags.dynamic == TRUE){
if(cmd_flags.search_paths_first == TRUE){
file_name = search_paths_for_lname(start);
}
else{
p = makestr("lib", start, ".dylib", NULL);
file_name = search_for_file(p);
free(p);
if(file_name == NULL){
p = makestr("lib", start, ".a", NULL);
file_name = search_for_file(p);
free(p);
}
}
}
else{
p = makestr("lib", start, ".a", NULL);
file_name = search_for_file(p);
free(p);
}
}
if(file_name == NULL)
error("can't locate file for: %s", l_flag);
return(file_name);
}
static
char *
search_for_file(
char *base_name)
{
unsigned long i;
char *file_name;
for(i = 0; i < cmd_flags.nLdirs ; i++){
if(cmd_flags.Ldirs[i][1] != 'L')
continue;
file_name = makestr(cmd_flags.Ldirs[i] + 2, "/", base_name, NULL);
if(access(file_name, R_OK) != -1)
return(file_name);
free(file_name);
}
for(i = 0; standard_dirs[i] != NULL ; i++){
file_name = makestr(standard_dirs[i], base_name, NULL);
if(access(file_name, R_OK) != -1)
return(file_name);
free(file_name);
}
return(NULL);
}
static
char *
search_paths_for_lname(
const char *lname_argument)
{
unsigned long i;
char *file_name, *dir;
for(i = 0; i < cmd_flags.nLdirs ; i++){
if(cmd_flags.Ldirs[i][1] != 'L')
continue;
dir = makestr(cmd_flags.Ldirs[i] + 2, "/", NULL);
file_name = search_path_for_lname(dir, lname_argument);
free(dir);
if(file_name != NULL)
return(file_name);
}
for(i = 0; standard_dirs[i] != NULL ; i++){
file_name = search_path_for_lname(standard_dirs[i], lname_argument);
if(file_name != NULL)
return(file_name);
}
return(NULL);
}
static
char *
search_path_for_lname(
const char *dir,
const char *lname_argument)
{
char *file_name;
file_name = makestr(dir, "/", "lib", lname_argument, ".dylib", NULL);
if(access(file_name, R_OK) != -1)
return(file_name);
free(file_name);
file_name = makestr(dir, "/", "lib", lname_argument, ".a", NULL);
if(access(file_name, R_OK) != -1)
return(file_name);
free(file_name);
return(NULL);
}
static
void
add_member(
struct ofile *ofile)
{
unsigned long i, j, size, ar_name_size;
struct arch *arch;
struct member *member;
struct stat stat_buf;
char *p, c, ar_name_buf[sizeof(ofile->member_ar_hdr->ar_name) + 1];
char ar_size_buf[sizeof(ofile->member_ar_hdr->ar_size) + 1];
const struct arch_flag *family_arch_flag;
long k;
enum bool has_space_in_name;
if(ofile->member_ar_hdr == NULL){
if(stat(ofile->file_name, &stat_buf) == -1){
system_error("can't stat file: %s", ofile->file_name);
return;
}
}
if(ofile->mh != NULL)
size = round(ofile->object_size, sizeof(long));
else{
size = round(ofile->member_size, sizeof(long));
}
i = 0;
if(ofile->mh != NULL){
if(ofile->mh->cputype == 0){
if(ofile->member_ar_hdr != NULL){
error("file: %s(%.*s) cputype is zero (a reserved value)",
ofile->file_name, (int)ofile->member_name_size,
ofile->member_name);
}
else
error("file: %s cputype is zero (a reserved value)",
ofile->file_name);
return;
}
if(ofile->mh->filetype == MH_DYLIB ||
ofile->mh->filetype == MH_DYLIB_STUB){
if(cmd_flags.dynamic != TRUE){
if(ofile->member_ar_hdr != NULL){
warning("file: %s(%.*s) is a dynamic library, not "
"added to the static library",
ofile->file_name, (int)ofile->member_name_size,
ofile->member_name);
}
else
warning("file: %s is a dynamic library, not added to "
"the static library", ofile->file_name);
}
return;
}
if(cmd_flags.arch_only_flag.name != NULL &&
cmd_flags.arch_only_flag.cputype != ofile->mh->cputype)
return;
for( ; i < narchs; i++){
if(archs[i].arch_flag.cputype == ofile->mh->cputype)
break;
}
}
if(narchs == 1 && archs[0].arch_flag.cputype == 0){
i = 0;
}
else if(i == narchs){
archs = reallocate(archs, sizeof(struct arch) * (narchs+1));
memset(archs + narchs, '\0', sizeof(struct arch));
if(ofile->mh != NULL){
family_arch_flag =
get_arch_family_from_cputype(ofile->mh->cputype);
if(family_arch_flag != NULL)
archs[narchs].arch_flag = *family_arch_flag;
}
else
archs[narchs].arch_flag.name = "unknown";
narchs++;
}
arch = archs + i;
if(arch->arch_flag.cputype == 0 && ofile->mh != NULL){
family_arch_flag = get_arch_family_from_cputype(ofile->mh->cputype);
if(family_arch_flag != NULL){
arch->arch_flag = *family_arch_flag;
}
else{
arch->arch_flag.name =
savestr("cputype 1234567890 cpusubtype 1234567890");
if(arch->arch_flag.name != NULL)
sprintf(arch->arch_flag.name, "cputype %u cpusubtype %u",
ofile->mh->cputype, ofile->mh->cpusubtype);
arch->arch_flag.cputype = ofile->mh->cputype;
arch->arch_flag.cpusubtype = ofile->mh->cpusubtype;
}
}
arch->members = reallocate(arch->members, sizeof(struct member) *
(arch->nmembers + 1));
member = arch->members + arch->nmembers;
memset(member, '\0', sizeof(struct member));
arch->nmembers++;
member->input_file_name = ofile->file_name;
if(ofile->member_ar_hdr == NULL){
p = strrchr(ofile->file_name, '/');
if(p != NULL)
p++;
else
p = ofile->file_name;
member->input_base_name = p;
member->input_base_name_size = strlen(p);
member->member_name = member->input_base_name;
if(cmd_flags.use_long_names == TRUE &&
(member->input_base_name_size >
sizeof(member->ar_hdr.ar_name) ||
strchr(member->input_base_name, ' ') != NULL)){
member->output_long_name = TRUE;
member->member_name_size = member->input_base_name_size;
ar_name_size =
round(member->input_base_name_size, sizeof(unsigned long));
sprintf(ar_name_buf, "%s%-*lu", AR_EFMT1,
(int)(sizeof(member->ar_hdr.ar_name) -
(sizeof(AR_EFMT1) - 1)), ar_name_size);
memcpy(member->ar_hdr.ar_name, ar_name_buf,
sizeof(member->ar_hdr.ar_name));
}
else{
ar_name_size = 0;
member->output_long_name = FALSE;
c = '\0';
if(strlen(p) > sizeof(member->ar_hdr.ar_name)){
c = p[sizeof(member->ar_hdr.ar_name)];
p[sizeof(member->ar_hdr.ar_name)] = '\0';
}
sprintf((char *)(&member->ar_hdr), "%-*s",
(int)sizeof(member->ar_hdr.ar_name), p);
if(c != '\0')
p[sizeof(member->ar_hdr.ar_name)] = c;
member->member_name_size = size_ar_name(&member->ar_hdr);
}
sprintf((char *)(&member->ar_hdr) + sizeof(member->ar_hdr.ar_name),
"%-*ld%-*u%-*u%-*o%-*ld%-*s",
(int)sizeof(member->ar_hdr.ar_date),
(long int)stat_buf.st_mtime,
(int)sizeof(member->ar_hdr.ar_uid),
(unsigned short)stat_buf.st_uid,
(int)sizeof(member->ar_hdr.ar_gid),
(unsigned short)stat_buf.st_gid,
(int)sizeof(member->ar_hdr.ar_mode),
(unsigned int)stat_buf.st_mode,
(int)sizeof(member->ar_hdr.ar_size),
(long)size + ar_name_size,
(int)sizeof(member->ar_hdr.ar_fmag),
ARFMAG);
}
else{
member->input_ar_hdr = ofile->member_ar_hdr;
member->input_base_name = ofile->member_name;
member->input_base_name_size = ofile->member_name_size;
member->ar_hdr = *(ofile->member_ar_hdr);
member->member_name = ofile->member_name;
if(cmd_flags.use_long_names == TRUE){
if(ofile->member_name != ofile->member_ar_hdr->ar_name){
member->output_long_name = TRUE;
member->member_name_size = ofile->member_name_size;
ar_name_size = round(ofile->member_name_size,
sizeof(unsigned long));
sprintf(ar_name_buf, "%s%-*lu", AR_EFMT1,
(int)(sizeof(member->ar_hdr.ar_name) -
(sizeof(AR_EFMT1) - 1)), ar_name_size);
memcpy(member->ar_hdr.ar_name, ar_name_buf,
sizeof(member->ar_hdr.ar_name));
}
else{
for(k = sizeof(member->ar_hdr.ar_name) - 1 ; k > 0 ; k--)
if(ofile->member_name[k] != ' ')
break;
has_space_in_name = FALSE;
for( ; k > 0 ; k--){
if(ofile->member_name[k] == ' '){
has_space_in_name = TRUE;
break;
}
}
member->member_name_size = size_ar_name(&member->ar_hdr);
if(has_space_in_name == TRUE){
ar_name_size = round(member->member_name_size,
sizeof(unsigned long));
member->output_long_name = TRUE;
sprintf(ar_name_buf, "%s%-*lu", AR_EFMT1,
(int)(sizeof(member->ar_hdr.ar_name) -
(sizeof(AR_EFMT1) - 1)), ar_name_size);
memcpy(member->ar_hdr.ar_name, ar_name_buf,
sizeof(member->ar_hdr.ar_name));
}
else{
ar_name_size = 0;
member->output_long_name = FALSE;
}
}
}
else{
ar_name_size = 0;
member->output_long_name = FALSE;
if(ofile->member_name != ofile->member_ar_hdr->ar_name){
for(j = 0; j < sizeof(member->ar_hdr.ar_name) &&
j < ofile->member_name_size &&
ofile->member_name[j] != '\0'; j++)
member->ar_hdr.ar_name[j] = ofile->member_name[j];
for( ; j < sizeof(member->ar_hdr.ar_name); j++)
member->ar_hdr.ar_name[j] = ' ';
}
member->member_name_size = size_ar_name(&member->ar_hdr);
}
sprintf(ar_size_buf, "%-*ld",
(int)sizeof(member->ar_hdr.ar_size),
(long)size + ar_name_size);
memcpy(member->ar_hdr.ar_size, ar_size_buf,
sizeof(member->ar_hdr.ar_size));
}
member->offset = arch->size;
arch->size += sizeof(struct ar_hdr) + size + ar_name_size;
if(ofile->mh != NULL){
member->object_addr = ofile->object_addr;
member->object_size = ofile->object_size;
member->object_byte_sex = ofile->object_byte_sex;
member->mh = ofile->mh;
member->load_commands = ofile->load_commands;
}
else{
member->object_addr = ofile->member_addr;
member->object_size = ofile->member_size;
}
}
static
void
free_archs(
void)
{
unsigned long i;
for(i = 0 ; i < narchs; i++){
if(archs[i].toc_ranlibs != NULL)
free(archs[i].toc_ranlibs);
if(archs[i].toc_strings != NULL)
free(archs[i].toc_strings);
if(archs[i].members != NULL)
free(archs[i].members);
}
if(archs != NULL)
free(archs);
archs = NULL;
narchs = 0;
}
static
void
create_library(
char *output)
{
unsigned long i, j, k, l, library_size, offset, pad, *time_offsets;
enum byte_sex target_byte_sex;
char *library, *p;
kern_return_t r;
struct arch *arch;
struct fat_header *fat_header;
struct fat_arch *fat_arch;
int fd;
#ifndef __OPENSTEP__
struct utimbuf timep;
#else
time_t timep[2];
#endif
struct stat stat_buf;
struct ar_hdr toc_ar_hdr;
if(narchs == 0){
if(cmd_flags.ranlib == TRUE){
warning("empty library: %s (no table of contents added)",
output);
return;
}
else{
if(cmd_flags.dynamic == FALSE ||
cmd_flags.no_files_ok == FALSE){
error("no library created (no object files in input "
"files)");
return;
}
}
}
if(cmd_flags.dynamic == TRUE){
create_dynamic_shared_library(output);
return;
}
if(cmd_flags.ranlib == FALSE)
warn_duplicate_member_names();
if(narchs > 1){
library_size = sizeof(struct fat_header) +
sizeof(struct fat_arch) * narchs;
if(cmd_flags.f == TRUE)
warning("archive library: %s will be fat and ar(1) will not "
"be able to operate on it", output);
}
else
library_size = 0;
for(i = 0; i < narchs; i++){
make_table_of_contents(archs + i, output);
archs[i].size += SARMAG + archs[i].toc_size;
library_size += archs[i].size;
}
if((r = vm_allocate(mach_task_self(), (vm_address_t *)&library,
library_size, TRUE)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_allocate() buffer for output file: %s of "
"size %lu", output, library_size);
if(narchs > 1){
fat_header = (struct fat_header *)library;
fat_header->magic = FAT_MAGIC;
fat_header->nfat_arch = narchs;
offset = sizeof(struct fat_header) +
sizeof(struct fat_arch) * narchs;
fat_arch = (struct fat_arch *)(library + sizeof(struct fat_header));
for(i = 0; i < narchs; i++){
fat_arch[i].cputype = archs[i].arch_flag.cputype;
fat_arch[i].cpusubtype = archs[i].arch_flag.cpusubtype;
fat_arch[i].offset = offset;
fat_arch[i].size = archs[i].size;
fat_arch[i].align = 2;
offset += archs[i].size;
}
#ifdef __LITTLE_ENDIAN__
swap_fat_header(fat_header, BIG_ENDIAN_BYTE_SEX);
swap_fat_arch(fat_arch, narchs, BIG_ENDIAN_BYTE_SEX);
#endif
offset = sizeof(struct fat_header) +
sizeof(struct fat_arch) * narchs;
}
else
offset = 0;
time_offsets = allocate(narchs * sizeof(unsigned long));
for(i = 0; i < narchs; i++){
p = library + offset;
arch = archs + i;
memcpy(p, ARMAG, SARMAG);
p += SARMAG;
if(arch->toc_nranlibs == 0){
if(narchs > 1)
warning("warning for library: %s for architecture: %s the "
"table of contents is empty (no object file members"
" in the library define global symbols)", output,
arch->arch_flag.name);
else
warning("warning for library: %s the table of contents is "
"empty (no object file members in the library "
"define global symbols)", output);
}
target_byte_sex = UNKNOWN_BYTE_SEX;
for(j = 0;
j < arch->nmembers && target_byte_sex == UNKNOWN_BYTE_SEX;
j++){
target_byte_sex = arch->members[j].object_byte_sex;
}
if(target_byte_sex == UNKNOWN_BYTE_SEX)
target_byte_sex = host_byte_sex;
time_offsets[i] =
(p - library) +
((char *)&toc_ar_hdr.ar_date - (char *)&toc_ar_hdr);
memcpy(p, (char *)&arch->toc_ar_hdr, sizeof(struct ar_hdr));
p += sizeof(struct ar_hdr);
if(arch->toc_long_name == TRUE){
memcpy(p, arch->toc_name, arch->toc_name_size);
p += arch->toc_name_size;
}
l = arch->toc_nranlibs * sizeof(struct ranlib);
if(target_byte_sex != host_byte_sex)
l = SWAP_LONG(l);
memcpy(p, (char *)&l, sizeof(long));
p += sizeof(long);
if(target_byte_sex != host_byte_sex)
swap_ranlib(arch->toc_ranlibs, arch->toc_nranlibs,
target_byte_sex);
memcpy(p, (char *)arch->toc_ranlibs,
arch->toc_nranlibs * sizeof(struct ranlib));
p += arch->toc_nranlibs * sizeof(struct ranlib);
l = arch->toc_strsize;
if(target_byte_sex != host_byte_sex)
l = SWAP_LONG(l);
memcpy(p, (char *)&l, sizeof(long));
p += sizeof(long);
memcpy(p, (char *)arch->toc_strings, arch->toc_strsize);
p += arch->toc_strsize;
for(j = 0; j < arch->nmembers; j++){
memcpy(p, (char *)&(arch->members[j].ar_hdr),
sizeof(struct ar_hdr));
p += sizeof(struct ar_hdr);
if(arch->members[j].output_long_name == TRUE){
strncpy(p, arch->members[j].member_name,
arch->members[j].member_name_size);
p += round(arch->members[j].member_name_size,
sizeof(unsigned long));
}
if(arch->members[j].mh != NULL &&
arch->members[j].object_byte_sex != host_byte_sex){
if(swap_object_headers(arch->members[j].mh,
arch->members[j].load_commands) == FALSE)
fatal("internal error: swap_object_headers() failed");
}
memcpy(p, arch->members[j].object_addr,
arch->members[j].object_size);
p += arch->members[j].object_size;
pad = round(arch->members[j].object_size, sizeof(long)) -
arch->members[j].object_size;
for(k = 0; k < pad; k++)
*p++ = '\n';
}
offset += arch->size;
}
(void)unlink(output);
if((fd = open(output, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1){
system_error("can't create output file: %s", output);
return;
}
if(write(fd, library, library_size) != (int)library_size){
system_error("can't write output file: %s", output);
return;
}
if(close(fd) == -1){
system_fatal("can't close output file: %s", output);
return;
}
if(stat(output, &stat_buf) == -1){
system_fatal("can't stat file output file: %s", output);
return;
}
if((fd = open(output, O_WRONLY, 0)) == -1){
system_error("can't open output file: %s", output);
return;
}
sprintf((char *)(&toc_ar_hdr), "%-*s%-*ld",
(int)sizeof(toc_ar_hdr.ar_name),
SYMDEF,
(int)sizeof(toc_ar_hdr.ar_date),
(long int)stat_buf.st_mtime + 5);
for(i = 0; i < narchs; i++){
if(lseek(fd, time_offsets[i], L_SET) == -1){
system_error("can't lseek in output file: %s", output);
return;
}
if(write(fd, &toc_ar_hdr.ar_date, sizeof(toc_ar_hdr.ar_date)) !=
sizeof(toc_ar_hdr.ar_date)){
system_error("can't write to output file: %s", output);
return;
}
}
if(close(fd) == -1){
system_fatal("can't close output file: %s", output);
return;
}
#ifndef __OPENSTEP__
timep.actime = stat_buf.st_mtime;
timep.modtime = stat_buf.st_mtime;
if(utime(output, &timep) == -1)
#else
timep[0] = stat_buf.st_mtime;
timep[1] = stat_buf.st_mtime;
if(utime(output, timep) == -1)
#endif
{
system_fatal("can't set the modifiy times in output file: %s",
output);
return;
}
if((r = vm_deallocate(mach_task_self(), (vm_address_t)library,
library_size)) != KERN_SUCCESS){
my_mach_error(r, "can't vm_deallocate() buffer for output file");
return;
}
}
static
void
tellProjectBuilder(
char *message,
char *arch_name,
char *fileName)
{
char message_buf[1024];
mach_port_t ProjectBuilder_port;
char *portName;
#if defined(__OPENSTEP__) || defined(__GONZO_BUNSEN_BEAKER__)
char *hostName;
hostName = getenv("MAKEHOST");
if(hostName == NULL)
hostName = "";
#endif
portName = getenv("MAKEPORT");
if(portName == NULL)
return;
#if defined(__OPENSTEP__) || defined(__GONZO_BUNSEN_BEAKER__)
if(netname_look_up(name_server_port, hostName, portName,
(int *)&ProjectBuilder_port) != KERN_SUCCESS)
return;
#else
if(bootstrap_look_up(bootstrap_port, portName,
(int *)&ProjectBuilder_port) != KERN_SUCCESS)
return;
#endif
if(ProjectBuilder_port == MACH_PORT_NULL)
return;
strcpy(message_buf, message);
strcat(message_buf, arch_name);
make_alert(ProjectBuilder_port,
-1,
NULL, 0,
fileName, strlen(fileName)+1 > 1024 ? 1024 : strlen(fileName)+1,
NULL, 0,
0,
message_buf, strlen(message_buf) + 1);
}
static
void
create_dynamic_shared_library(
char *output)
{
unsigned long i, j;
char *p, *filelist;
struct stat stat_buf;
enum bool use_force_cpusubtype_ALL;
const struct arch_flag *family_arch_flag;
if(narchs > 1)
signal(SIGINT, create_dynamic_shared_library_cleanup);
use_force_cpusubtype_ALL = TRUE;
if(cmd_flags.arch_only_flag.name != NULL){
family_arch_flag = get_arch_family_from_cputype(
cmd_flags.arch_only_flag.cputype);
if(family_arch_flag != NULL){
if(family_arch_flag->cpusubtype !=
cmd_flags.arch_only_flag.cpusubtype)
use_force_cpusubtype_ALL = FALSE;
}
}
for(i = 0; i < narchs || (i == 0 && narchs == 0); i++){
reset_execute_list();
add_execute_list("ld");
if(narchs != 0 && cmd_flags.arch_only_flag.name == NULL)
add_execute_list("-arch_multiple");
if(archs != NULL){
add_execute_list("-arch");
if(use_force_cpusubtype_ALL == TRUE)
add_execute_list(archs[i].arch_flag.name);
else
add_execute_list(cmd_flags.arch_only_flag.name);
}
add_execute_list("-dylib");
add_execute_list("-dynamic");
if(cmd_flags.all_load_flag_specified == FALSE ||
cmd_flags.all_load == TRUE)
add_execute_list("-all_load");
if(use_force_cpusubtype_ALL == TRUE)
add_execute_list("-force_cpusubtype_ALL");
add_execute_list("-no_arch_warnings");
if(cmd_flags.seg1addr != NULL){
add_execute_list("-seg1addr");
add_execute_list(cmd_flags.seg1addr);
}
if(cmd_flags.segs_read_only_addr != NULL){
add_execute_list("-segs_read_only_addr");
add_execute_list(cmd_flags.segs_read_only_addr);
}
if(cmd_flags.segs_read_write_addr != NULL){
add_execute_list("-segs_read_write_addr");
add_execute_list(cmd_flags.segs_read_write_addr);
}
if(cmd_flags.seg_addr_table != NULL){
add_execute_list("-seg_addr_table");
add_execute_list(cmd_flags.seg_addr_table);
}
if(cmd_flags.seg_addr_table_filename != NULL){
add_execute_list("-seg_addr_table_filename");
add_execute_list(cmd_flags.seg_addr_table_filename);
}
if(cmd_flags.compatibility != NULL){
add_execute_list("-dylib_compatibility_version");
add_execute_list(cmd_flags.compatibility);
}
if(cmd_flags.current != NULL){
add_execute_list("-dylib_current_version");
add_execute_list(cmd_flags.current);
}
if(cmd_flags.install_name != NULL){
add_execute_list("-dylib_install_name");
add_execute_list(cmd_flags.install_name);
}
else{
if(narchs > 1){
add_execute_list("-dylib_install_name");
add_execute_list(cmd_flags.output);
}
}
for(j = 0; j < cmd_flags.nldflags; j++)
add_execute_list(cmd_flags.ldflags[j]);
for(j = 0; j < cmd_flags.nLdirs; j++)
add_execute_list(cmd_flags.Ldirs[j]);
add_execute_list("-ldylib1.o");
filelist = NULL;
for(j = 0; j < cmd_flags.nfiles; j++){
if(cmd_flags.filelist[j] == NULL){
add_execute_list(cmd_flags.files[j]);
}
else{
if(cmd_flags.filelist[j] != filelist){
add_execute_list("-filelist");
add_execute_list(cmd_flags.filelist[j]);
filelist = cmd_flags.filelist[j];
}
}
}
if(narchs <= 1){
add_execute_list("-o");
add_execute_list(cmd_flags.output);
tellProjectBuilder("Linking %s", "", cmd_flags.output);
}
else{
add_execute_list("-o");
add_execute_list(makestr(cmd_flags.output, ".libtool.",
archs[i].arch_flag.name, NULL));
if(cmd_flags.final_output_specified == FALSE){
add_execute_list("-final_output");
add_execute_list(cmd_flags.output);
}
tellProjectBuilder("Linking %s for ", archs[i].arch_flag.name,
cmd_flags.output);
}
if(execute_list(cmd_flags.verbose) == 0)
fatal("internal link edit command failed");
}
if(narchs > 1){
tellProjectBuilder("Combining into %s", "", cmd_flags.output);
reset_execute_list();
add_execute_list("lipo");
add_execute_list("-create");
add_execute_list("-output");
add_execute_list(cmd_flags.output);
for(i = 0; i < narchs; i++){
add_execute_list(makestr(cmd_flags.output, ".libtool.",
archs[i].arch_flag.name, NULL));
}
if(execute_list(cmd_flags.verbose) == 0)
fatal("internal lipo command failed");
for(i = 0; i < narchs; i++){
p = makestr(cmd_flags.output, ".libtool.",
archs[i].arch_flag.name, NULL);
if(unlink(p) == -1){
error("can't remove temporary file: %s", p);
}
}
}
if(cmd_flags.prebinding == TRUE){
if(stat("/usr/bin/objcunique", &stat_buf) != -1){
reset_execute_list();
add_execute_list("/usr/bin/objcunique");
add_execute_list(cmd_flags.output);
add_execute_list("-prebind");
for(j = 0; j < cmd_flags.nLdirs; j++)
add_execute_list(cmd_flags.Ldirs[j]);
if(execute_list(cmd_flags.verbose) == 0)
fatal("internal /usr/bin/objcunique command failed");
}
}
}
static
void
create_dynamic_shared_library_cleanup(
int sig)
{
unsigned long i;
for(i = 0; i < narchs; i++){
(void)unlink(makestr(cmd_flags.output, ".libtool.",
archs[i].arch_flag.name, NULL));
}
exit(EXIT_FAILURE);
}
static
void
make_table_of_contents(
struct arch *arch,
char *output)
{
unsigned long i, j, k, r, s, nsects;
struct member *member;
struct load_command *lc;
struct segment_command *sg;
struct nlist *symbols;
char *strings;
enum bool sorted;
char *ar_name;
struct section *section;
for(i = 0; i < arch->nmembers; i++){
member = arch->members + i;
if(member->mh != NULL){
nsects = 0;
lc = member->load_commands;
for(j = 0; j < member->mh->ncmds; j++){
if(lc->cmd == LC_SYMTAB){
if(member->st == NULL)
member->st = (struct symtab_command *)lc;
}
else if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
nsects += sg->nsects;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
member->sections = allocate(nsects * sizeof(struct section *));
nsects = 0;
lc = member->load_commands;
for(j = 0; j < member->mh->ncmds; j++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
section = (struct section *)
((char *)sg + sizeof(struct segment_command));
for(k = 0; k < sg->nsects; k++){
member->sections[nsects++] = section++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(member->st != NULL && member->st->nsyms != 0){
symbols = (struct nlist *)(member->object_addr +
member->st->symoff);
if(member->object_byte_sex != get_host_byte_sex())
swap_nlist(symbols, member->st->nsyms,
get_host_byte_sex());
strings = member->object_addr + member->st->stroff;
for(j = 0; j < member->st->nsyms; j++){
if((unsigned long)symbols[j].n_un.n_strx >
member->st->strsize){
warn_member(arch, member, "malformed object (symbol"
" %lu n_strx field extends past the "
"end of the string table)", j);
continue;
}
if(toc_symbol(symbols + j, member->sections) == TRUE){
arch->toc_nranlibs++;
arch->toc_strsize += strlen(strings +
symbols[j].n_un.n_strx) + 1;
}
}
}
else
warn_member(arch, member, "has no symbols");
}
else{
if(cmd_flags.ranlib == FALSE){
warn_member(arch, member, "is not an object file");
errors++;
}
}
}
arch->toc_ranlibs = allocate(sizeof(struct ranlib) *arch->toc_nranlibs);
arch->toc_strsize = round(arch->toc_strsize, sizeof(long));
arch->toc_strings = allocate(arch->toc_strsize);
r = 0;
s = 0;
for(i = 0; i < arch->nmembers; i++){
member = arch->members + i;
if(member->mh != NULL){
if(member->st != NULL && member->st->nsyms != 0){
symbols = (struct nlist *)(member->object_addr +
member->st->symoff);
strings = member->object_addr + member->st->stroff;
for(j = 0; j < member->st->nsyms; j++){
if(symbols[j].n_un.n_strx > (long)member->st->strsize)
continue;
if(toc_symbol(symbols + j, member->sections) == TRUE){
strcpy(arch->toc_strings + s,
strings + symbols[j].n_un.n_strx);
arch->toc_ranlibs[r].ran_un.ran_name =
arch->toc_strings + s;
arch->toc_ranlibs[r].ran_off = i + 1;
r++;
s += strlen(strings + symbols[j].n_un.n_strx) + 1;
}
}
if(member->object_byte_sex != get_host_byte_sex())
swap_nlist(symbols, member->st->nsyms,
get_host_byte_sex());
}
}
}
if(cmd_flags.s == TRUE){
qsort(arch->toc_ranlibs, arch->toc_nranlibs, sizeof(struct ranlib),
(int (*)(const void *, const void *))ranlib_name_qsort);
sorted = check_sort_ranlibs(arch, output);
if(sorted == FALSE){
qsort(arch->toc_ranlibs, arch->toc_nranlibs,
sizeof(struct ranlib),
(int (*)(const void *, const void *))ranlib_offset_qsort);
arch->toc_name = SYMDEF;
arch->toc_name_size = sizeof(SYMDEF) - 1;
arch->toc_long_name = FALSE;
ar_name = arch->toc_name;
}
else{
arch->toc_name = SYMDEF_SORTED;
arch->toc_name_size = sizeof(SYMDEF_SORTED) - 1;
if(cmd_flags.use_long_names == TRUE){
arch->toc_long_name = TRUE;
ar_name = AR_EFMT1 "16";
}
else{
arch->toc_long_name = FALSE;
ar_name = arch->toc_name;
}
}
}
else{
sorted = FALSE;
arch->toc_name = SYMDEF;
arch->toc_name_size = sizeof(SYMDEF) - 1;
arch->toc_long_name = FALSE;
ar_name = arch->toc_name;
}
arch->toc_size = sizeof(struct ar_hdr) +
sizeof(long) +
arch->toc_nranlibs * sizeof(struct ranlib) +
sizeof(long) +
arch->toc_strsize;
if(arch->toc_long_name == TRUE)
arch->toc_size += arch->toc_name_size;
for(i = 0; i < arch->nmembers; i++)
arch->members[i].offset += SARMAG + arch->toc_size;
for(i = 0; i < arch->toc_nranlibs; i++){
arch->toc_ranlibs[i].ran_un.ran_strx =
arch->toc_ranlibs[i].ran_un.ran_name - arch->toc_strings;
arch->toc_ranlibs[i].ran_off =
arch->members[arch->toc_ranlibs[i].ran_off - 1].offset;
}
sprintf((char *)(&arch->toc_ar_hdr), "%-*s%-*ld%-*u%-*u%-*o%-*ld",
(int)sizeof(arch->toc_ar_hdr.ar_name),
ar_name,
(int)sizeof(arch->toc_ar_hdr.ar_date),
toc_time,
(int)sizeof(arch->toc_ar_hdr.ar_uid),
(unsigned short)getuid(),
(int)sizeof(arch->toc_ar_hdr.ar_gid),
(unsigned short)getgid(),
(int)sizeof(arch->toc_ar_hdr.ar_mode),
(unsigned int)toc_mode,
(int)sizeof(arch->toc_ar_hdr.ar_size),
(long)(arch->toc_size - sizeof(struct ar_hdr)));
memcpy(arch->toc_ar_hdr.ar_fmag, ARFMAG,
(int)sizeof(arch->toc_ar_hdr.ar_fmag));
}
static
int
ranlib_name_qsort(
const struct ranlib *ran1,
const struct ranlib *ran2)
{
return(strcmp(ran1->ran_un.ran_name, ran2->ran_un.ran_name));
}
static
int
ranlib_offset_qsort(
const struct ranlib *ran1,
const struct ranlib *ran2)
{
if(ran1->ran_off < ran2->ran_off)
return(-1);
if(ran1->ran_off > ran2->ran_off)
return(1);
return(0);
}
static
enum bool
toc_symbol(
struct nlist *symbol,
struct section **sections)
{
if(symbol->n_un.n_strx == 0)
return(FALSE);
if((symbol->n_type & N_EXT) == 0)
return(FALSE);
if((symbol->n_type & N_TYPE) == N_UNDF && symbol->n_value == 0)
return(FALSE);
if((symbol->n_type & N_TYPE) == N_UNDF && symbol->n_value != 0 &&
cmd_flags.c == FALSE)
return(FALSE);
if((symbol->n_type & N_TYPE) == N_SECT &&
(sections[symbol->n_sect - 1]->flags & S_ATTR_NO_TOC) != 0)
return(FALSE);
return(TRUE);
}
static
enum bool
check_sort_ranlibs(
struct arch *arch,
char *output)
{
unsigned long i;
enum bool multiple_defs;
struct member *member;
if(arch->toc_nranlibs == 0)
return(TRUE);
multiple_defs = FALSE;
for(i = 0; i < arch->toc_nranlibs - 1; i++){
if(strcmp(arch->toc_ranlibs[i].ran_un.ran_name,
arch->toc_ranlibs[i+1].ran_un.ran_name) == 0){
if(multiple_defs == FALSE){
fprintf(stderr, "%s: same symbol defined in more than one "
"member ", progname);
if(narchs > 1)
fprintf(stderr, "for architecture: %s ",
arch->arch_flag.name);
fprintf(stderr, "in: %s (table of contents will not be "
"sorted)\n", output);
multiple_defs = TRUE;
}
if((int)(arch->toc_ranlibs[i].ran_off) > 0){
member = arch->members + arch->toc_ranlibs[i].ran_off - 1;
warn_member(arch, member, "defines symbol: %s",
arch->toc_ranlibs[i].ran_un.ran_name);
arch->toc_ranlibs[i].ran_off =
-(arch->toc_ranlibs[i].ran_off);
}
if((int)(arch->toc_ranlibs[i+1].ran_off) > 0){
member = arch->members + arch->toc_ranlibs[i+1].ran_off - 1;
warn_member(arch, member, "defines symbol: %s",
arch->toc_ranlibs[i+1].ran_un.ran_name);
arch->toc_ranlibs[i+1].ran_off =
-(arch->toc_ranlibs[i+1].ran_off);
}
}
}
if(multiple_defs == FALSE)
return(TRUE);
else{
for(i = 0; i < arch->toc_nranlibs; i++)
if(((int)arch->toc_ranlibs[i].ran_off) < 0)
arch->toc_ranlibs[i].ran_off =
-(arch->toc_ranlibs[i].ran_off);
return(FALSE);
}
}
static
void
warn_duplicate_member_names(
void)
{
unsigned long i, j, len, len1, len2;
for(i = 0; i < narchs; i++){
qsort(archs[i].members, archs[i].nmembers, sizeof(struct member),
(int (*)(const void *, const void *))member_name_qsort);
for(j = 0; j < archs[i].nmembers - 1; j++){
len1 = archs[i].members[j].member_name_size;
len2 = archs[i].members[j+1].member_name_size;
len = len1 > len2 ? len1 : len2;
if(strncmp(archs[i].members[j].member_name,
archs[i].members[j+1].member_name,
len) == 0){
fprintf(stderr, "%s: warning ", progname);
if(narchs > 1)
fprintf(stderr, "for architecture: %s ",
archs[i].arch_flag.name);
fprintf(stderr, "same member name (%.*s) in output file "
"used for input files: ", (int)len1,
archs[i].members[j].member_name);
if(archs[i].members[j].input_ar_hdr != NULL){
len = archs[i].members[j].input_base_name_size;
fprintf(stderr, "%s(%.*s) and: ",
archs[i].members[j].input_file_name, (int)len,
archs[i].members[j].input_base_name);
}
else
fprintf(stderr, "%s and: ",
archs[i].members[j].input_file_name);
if(archs[i].members[j+1].input_ar_hdr != NULL){
len = archs[i].members[j+1].input_base_name_size;
fprintf(stderr, "%s(%.*s) due to use of basename, "
"truncation and blank padding\n",
archs[i].members[j+1].input_file_name, (int)len,
archs[i].members[j+1].input_base_name);
}
else
fprintf(stderr, "%s (due to use of basename, truncation"
", blank padding or duplicate input files)\n",
archs[i].members[j+1].input_file_name);
}
}
qsort(archs[i].members, archs[i].nmembers, sizeof(struct member),
(int (*)(const void *, const void *))member_offset_qsort);
}
}
static
int
member_name_qsort(
const struct member *member1,
const struct member *member2)
{
unsigned long len, len1, len2;
len1 = member1->member_name_size;
len2 = member2->member_name_size;
len = len1 > len2 ? len1 : len2;
return(strncmp(member1->member_name, member2->member_name, len));
}
static
int
member_offset_qsort(
const struct member *member1,
const struct member *member2)
{
if(member1->offset < member2->offset)
return(-1);
if(member1->offset > member2->offset)
return(1);
return(0);
}
static
void
warn_member(
struct arch *arch,
struct member *member,
const char *format, ...)
{
va_list ap;
fprintf(stderr, "%s: ", progname);
if(narchs > 1)
fprintf(stderr, "for architecture: %s ", arch->arch_flag.name);
if(member->input_ar_hdr != NULL){
fprintf(stderr, "file: %s(%.*s) ", member->input_file_name,
(int)member->input_base_name_size, member->input_base_name);
}
else
fprintf(stderr, "file: %s ", member->input_file_name);
va_start(ap, format);
vfprintf(stderr, format, ap);
fprintf(stderr, "\n");
va_end(ap);
}