Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Add machista library from MacPorts trunk r129895.
Landon Fuller committed 11 years ago
commit 00551dc57064c9bfaa57ec013b28f4691063745a
parent eb48e9d
7 files changed +1212 -0
modified external/Makefile.am
@@ -45,6 +45,8 @@ noinst_HEADERS= expat/amiga/expat_68k.h \
		libelf/elfdefinitions.h \
		libelf/gelf.h \
		libelf/libelf.h \
+
		libmachista/hashmap.h \
+
		libmachista/libmachista.h \
		libsbuf/sys/sbuf.h \
		libucl/include/ucl.h \
		libucl/src/xxhash.h \
@@ -79,6 +81,10 @@ DYNLIBS+= libelf.la
noinst_LTLIBRARIES+=	libelf_static.la
endif

+
if HAVE_MACHO_ABI
+
noinst_LTLIBRARIES+=	libmachista_static.la
+
endif
+

if DYNAMIC
noinst_LTLIBRARIES+=	$(DYNLIBS)
endif
@@ -146,6 +152,11 @@ libelf_static_la_SOURCES= ${libelf_la_SOURCES}
libelf_static_la_CFLAGS=	$(libelf_la_CFLAGS) -static
libelf_static_la_LDFLAGS=	-all-static

+
libmachista_static_la_SOURCES=	libmachista/libmachista.c \
+
				libmachista/hashmap.c
+
libmachista_static_la_CFLAGS=	-I$(tip_srcdir)/external/libmachista -static
+
libmachista_static_la_LDFLAGS=	-all-static
+

libsbuf_la_SOURCES=	libsbuf/subr_sbuf.c
sbuf_common_CFLAGS=	-I$(top_srcdir)/external/libsbuf
libsbuf_la_CFLAGS=	$(sbuf_common_CFLAGS) -shared
added external/libmachista/LICENSE
@@ -0,0 +1,52 @@
+
Copyright (c) 2011 Clemens Lang <cal@macports.org>
+
Copyright (c) 2011 - 2014 Landon Fuller <landonf@macports.org>
+
Copyright (c) 2004 - 2014, The MacPorts Project.
+
Copyright (c) 2002 - 2003, Apple Inc.
+
All rights reserved.
+

+
Redistribution and use in source and binary forms, with or without
+
modification, are permitted provided that the following conditions
+
are met:
+
1. Redistributions of source code must retain the above copyright
+
   notice, this list of conditions and the following disclaimer.
+
2. Redistributions in binary form must reproduce the above copyright
+
   notice, this list of conditions and the following disclaimer in the
+
   documentation and/or other materials provided with the distribution.
+
3. Neither the name of Apple Inc., The MacPorts Project nor the
+
   names of its contributors may be used to endorse or promote products
+
   derived from this software without specific prior written permission.
+

+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+
SUCH DAMAGE.
+

+
hashmap.c is subject to the following license:
+

+
Copyright (c) 2011 Christoph Erhardt. All rights reserved.
+

+
Redistribution and use in source and binary forms, with or without
+
modification, are permitted provided that the following conditions are met:
+
1. Redistributions of source code must retain the above copyright notice,
+
   this list of conditions and the following disclaimer.
+
2. Redistributions in binary form must reproduce the above copyright notice,
+
   this list of conditions and the following disclaimer in the documentation
+
   and/or other materials provided with the distribution.
+

+
THIS SOFTWARE IS PROVIDED BY CHRISTOPH ERHARDT ``AS IS'' AND ANY EXPRESS OR
+
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+
EVENT SHALL CHRISTOPH ERHARDT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
added external/libmachista/hashmap.c
@@ -0,0 +1,295 @@
+
/* vim:expandtab:tw=80:ts=2:sts=2:sw=2
+
 */
+
/*-
+
 * Copyright (c) 2011 Christoph Erhardt. All rights reserved.
+
 *
+
 * Redistribution and use in source and binary forms, with or without
+
 * modification, are permitted provided that the following conditions are met:
+
 * 1. Redistributions of source code must retain the above copyright notice,
+
 *    this list of conditions and the following disclaimer.
+
 * 2. Redistributions in binary form must reproduce the above copyright notice,
+
 *    this list of conditions and the following disclaimer in the documentation
+
 *    and/or other materials provided with the distribution.
+
 *
+
 * THIS SOFTWARE IS PROVIDED BY CHRISTOPH ERHARDT ``AS IS'' AND ANY EXPRESS OR
+
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+
 * EVENT SHALL CHRISTOPH ERHARDT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 */
+
/*-
+
 * Modified by Clemens Lang to accept values of arbitrary type.
+
 */
+

+

+
#ifndef _BSD_SOURCE
+
  #define _BSD_SOURCE
+
#endif
+
#ifndef _CRT_NONSTDC_NO_DEPRECATE
+
  #define _CRT_NONSTDC_NO_DEPRECATE
+
#endif
+

+
#include "hashmap.h"
+
#include <limits.h>
+
#include <stdint.h>
+
#include <string.h>
+

+

+
static const size_t INITIAL_CAPACITY = 16; /* Must be a power of 2 */
+
static const size_t MAXIMUM_CAPACITY = (1U << 31);
+
static const float  LOAD_FACTOR      = 0.75;
+

+

+
typedef struct HashMapEntry {
+
  char                *key;
+
  const void          *value;
+
  struct HashMapEntry *next;
+
  uint32_t             hash;
+
} HashMapEntry;
+

+
struct HashMap {
+
  HashMapEntry **table;
+
  size_t         capacity;
+
  size_t         size;
+
  size_t         threshold;
+
  void         (*freeFunc)(const void *);
+
};
+

+

+
static void setTable(HashMap *map, HashMapEntry **table, size_t capacity) {
+
  map->table     = table;
+
  map->capacity  = capacity;
+
  map->threshold = (size_t) (capacity * LOAD_FACTOR);
+
}
+

+

+
static uint32_t doHash(const char key[]) {
+
  size_t   length;
+
  size_t   i;
+
  uint32_t h = 0;
+
  if (key == NULL)
+
    return 0;
+
  length = strlen(key);
+
  for (i = 0; i < length; ++i) {
+
    h = (31 * h) + key[i];
+
  }
+
  h ^= (h >> 20) ^ (h >> 12);
+
  return h ^ (h >> 7) ^ (h >> 4);
+
}
+

+

+
static size_t indexFor(uint32_t hash, size_t length) {
+
  return hash & (length - 1);
+
}
+

+

+
static int isHit(HashMapEntry *e, const char key[], uint32_t hash) {
+
  return (e->hash == hash
+
          && (e->key == key || (key != NULL && strcmp(e->key, key) == 0)));
+
}
+

+

+
static void copyOrFree(void (*freeFunc)(const void *),
+
                       const void *value, const void **valPtr) {
+
  if (valPtr != NULL)
+
    *valPtr = value;
+
  else
+
    freeFunc(value);
+
}
+

+

+
static int updateValue(HashMap *map, HashMapEntry *e, const void *newVal,
+
                       const void **oldValPtr) {
+
  copyOrFree(map->freeFunc, e->value, oldValPtr);
+
  e->value = newVal;
+
  return 1;
+
}
+

+

+
/* Creates a hash map. */
+
HashMap *hashMapCreate(void (*freeFunc)(const void *)) {
+
  HashMapEntry **table;
+
  HashMap       *map = malloc(sizeof(*map));
+
  if (map == NULL)
+
    return NULL;
+
  table = calloc(INITIAL_CAPACITY, sizeof(*map->table));
+
  if (table == NULL) {
+
    free(map);
+
    return NULL;
+
  }
+
  setTable(map, table, INITIAL_CAPACITY);
+
  map->size = 0;
+
  map->freeFunc = freeFunc;
+
  return map;
+
}
+

+

+
/* Inserts a key-value pair into a hash map. */
+
int hashMapPut(HashMap *map, const char key[], const void * const value,
+
               const void **oldValPtr) {
+

+
  HashMapEntry  *e;
+
  size_t         newCapacity;
+
  HashMapEntry **newTable;
+
  size_t         i;
+

+
  /* If an entry with the same key exists, update it */
+
  uint32_t hash  = doHash(key);
+
  size_t   index = indexFor(hash, map->capacity);
+
  for (e = map->table[index]; e != NULL; e = e->next) {
+
    if (isHit(e, key, hash) == 0)
+
      continue;
+
    return updateValue(map, e, value, oldValPtr);
+
  }
+

+
  /* Create a new entry */
+
  e = calloc(1, sizeof(HashMapEntry)); /* Must be zeroed */
+
  if (e == NULL)
+
    return 0;
+

+
  /* Copy key and value into the entry */
+
  if (key != NULL) {
+
    e->key = strdup(key);
+
    if (e->key == NULL) {
+
      free(e);
+
      return 0;
+
    }
+
  }
+
  if (updateValue(map, e, value, oldValPtr) == 0) {
+
    free(e->key);
+
    free(e);
+
    return 0;
+
  }
+

+
  /* Insert entry into the table */
+
  e->hash = hash;
+
  e->next = map->table[index];
+
  map->table[index] = e;
+
  if (map->size++ < map->threshold)
+
    return 1;
+

+
  /* If the size exceeds the threshold, double the table's capacity */
+
  newCapacity = 2 * map->capacity;
+
  if (map->capacity == MAXIMUM_CAPACITY) {
+
    map->threshold = UINT_MAX;
+
    return 1;
+
  }
+
  newTable = calloc(newCapacity, sizeof(*newTable));
+
  if (newTable == NULL)
+
    return 0;
+

+
  /* Copy entries from the old table into the new one */
+
  for (i = 0; i < map->capacity; ++i) {
+
    HashMapEntry *next;
+
    for (e = map->table[i]; e != NULL; e = next) {
+
      index   = indexFor(e->hash, newCapacity);
+
      next    = e->next;
+
      e->next = newTable[index];
+
      newTable[index] = e;
+
    }
+
  }
+

+
  /* Release the old table and set the new one */
+
  free(map->table);
+
  setTable(map, newTable, newCapacity);
+
  return 1;
+
}
+

+

+
/* Performs a hash map lookup. */
+
const void *hashMapGet(HashMap *map, const char key[]) {
+
  HashMapEntry *e;
+
  uint32_t      hash  = doHash(key);
+
  size_t        index = indexFor(hash, map->capacity);
+
  for (e = map->table[index]; e != NULL; e = e->next) {
+
    if (isHit(e, key, hash))
+
      return e->value;
+
  }
+
  return NULL;
+
}
+

+

+
/* Checks whether a hash map contains an entry with a certain key. */
+
int hashMapContainsKey(HashMap *map, const char key[]) {
+
  HashMapEntry *e;
+
  uint32_t      hash  = doHash(key);
+
  size_t        index = indexFor(hash, map->capacity);
+
  for (e = map->table[index]; e != NULL; e = e->next) {
+
    if (isHit(e, key, hash))
+
      return 1;
+
  }
+
  return 0;
+
}
+

+

+
/* Removes a key-value pair from a hash map. */
+
void hashMapRemove(HashMap *map, const char key[], const void **valPtr) {
+
  uint32_t      hash  = doHash(key);
+
  size_t        index = indexFor(hash, map->capacity);
+
  HashMapEntry *prev  = map->table[index];
+
  HashMapEntry *e     = prev;
+
  while (e != NULL) {
+
    HashMapEntry *next = e->next;
+
    if (isHit(e, key, hash)) {
+
      map->size--;
+
      if (prev == e)
+
        map->table[index] = next;
+
      else
+
        prev->next = next;
+
      break;
+
    }
+
    prev = e;
+
    e    = next;
+
  }
+
  if (e == NULL) {
+
    copyOrFree(map->freeFunc, NULL, valPtr);
+
    return;
+
  }
+
  free(e->key);
+
  copyOrFree(map->freeFunc, e->value, valPtr);
+
  free(e);
+
}
+

+

+
/* Returns the number of elements stored in a hash map. */
+
size_t hashMapSize(const HashMap *map) {
+
  return map->size;
+
}
+

+

+
/* Checks whether a hash map is empty. */
+
int hashMapIsEmpty(const HashMap *map) {
+
  return (map->size == 0);
+
}
+

+

+
/* Removes all entries from a hash map. */
+
void hashMapClear(HashMap *map) {
+
  size_t i;
+
  for (i = 0; i < map->capacity; ++i) {
+
    HashMapEntry *e;
+
    HashMapEntry *next;
+
    for (e = map->table[i]; e != NULL; e = next) {
+
      free(e->key);
+
      map->freeFunc(e->value);
+
      next = e->next;
+
      free(e);
+
    }
+
    map->table[i] = NULL;
+
  }
+
}
+

+

+
/* Destroys a hash map. */
+
void hashMapDestroy(HashMap *map) {
+
  if (map == NULL)
+
    return;
+
  hashMapClear(map);
+
  free(map->table);
+
  free(map);
+
}
added external/libmachista/hashmap.h
@@ -0,0 +1,135 @@
+
/* vim:tw=80:expandtab
+
 */
+
/**
+
 * @file  hashmap.h
+
 * @brief A hash map implementation in C.
+
 * @author Christoph Erhardt <erhardt@cs.fau.de>
+
 */
+

+
/*-
+
 * Copyright (c) 2011 Christoph Erhardt. All rights reserved.
+
 *
+
 * Redistribution and use in source and binary forms, with or without
+
 * modification, are permitted provided that the following conditions are met:
+
 * 1. Redistributions of source code must retain the above copyright notice,
+
 *    this list of conditions and the following disclaimer.
+
 * 2. Redistributions in binary form must reproduce the above copyright notice,
+
 *    this list of conditions and the following disclaimer in the documentation
+
 *    and/or other materials provided with the distribution.
+
 *
+
 * THIS SOFTWARE IS PROVIDED BY CHRISTOPH ERHARDT ``AS IS'' AND ANY EXPRESS OR
+
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+
 * EVENT SHALL CHRISTOPH ERHARDT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 */
+
/*-
+
 * Modified by Clemens Lang to accept values of arbitrary type.
+
 */
+

+

+
#ifndef HASHMAP_H
+
#define HASHMAP_H
+

+

+
#include <stdlib.h>
+

+

+
/** Hash map type. */
+
typedef struct HashMap HashMap;
+

+

+
/**
+
 * @brief Creates a hash map.
+
 *
+
 * The keys and values managed in the map can be arbitrary C strings.
+
 * @param freeFunc Function to call in order to free a stored value
+
 * @return Pointer to the newly created hash map, or @c NULL on error.
+
 */
+
HashMap *hashMapCreate(void (*freeFunc)(const void *));
+

+
/**
+
 * @brief Inserts a key-value pair into a hash map.
+
 *
+
 * Both key and value are copied internally, so the caller can reuse the
+
 * original variables.
+
 * If oldValPtr is @c NULL, the previously stored value corresponding to the key
+
 * is freed. Otherwise it is written into @c *valPtr and the caller is
+
 * responsible for freeing it.
+
 * @param map       Hash map.
+
 * @param key       Key.
+
 * @param value     Value.
+
 * @param oldValPtr Output parameter receiving the previously stored value
+
 *                  corresponding to the key (@c NULL if no mapping existed
+
 *                  before).
+
 * @return Nonzero on success, 0 on error.
+
 */
+
int hashMapPut(HashMap *map, const char key[], const void * const value,
+
               const void **oldValPtr);
+

+
/**
+
 * @brief Performs a hash map lookup.
+
 *
+
 * The returned value must not be freed or otherwise manipulated by the caller.
+
 * @param map Hash map.
+
 * @param key Key.
+
 * @return Value corresponding to the key on success, @c NULL if no matching
+
 *         entry was found.
+
 */
+
const void *hashMapGet(HashMap *map, const char key[]);
+

+
/**
+
 * @brief Checks whether a hash map contains an entry with a certain key.
+
 * @param map Hash map.
+
 * @param key Key.
+
 * @return Nonzero if the map contains an entry with the given key, 0 if it does
+
 *         not.
+
 */
+
int hashMapContainsKey(HashMap *map, const char key[]);
+

+
/**
+
 * @brief Removes a key-value pair from a hash map and frees the stored key.
+
 *
+
 * If @c valPtr is @c NULL, the internally stored value corresponding to the key
+
 * is freed. Otherwise it is written into @c *valPtr and the caller is
+
 * responsible for freeing it.
+
 * @param map    Hash map.
+
 * @param key    Key.
+
 * @param valPtr Output parameter receiving the internally stored value
+
 *               corresponding to the key.
+
 */
+
void hashMapRemove(HashMap *map, const char key[], const void **valPtr);
+

+
/**
+
 * @brief Returns the number of elements stored in a hash map.
+
 * @param map Hash map.
+
 * @return Number of elements stored in the map.
+
 */
+
size_t hashMapSize(const HashMap *map);
+

+
/**
+
 * @brief Checks whether a hash map is empty.
+
 * @param map Hash map.
+
 * @return Nonzero if the map contains no entries, 0 otherwise.
+
 */
+
int hashMapIsEmpty(const HashMap *map);
+

+
/**
+
 * @brief Removes all entries from a hash map.
+
 * @param map Hash map.
+
 */
+
void hashMapClear(HashMap *map);
+

+
/**
+
 * @brief Destroys a hash map.
+
 * @param map Hash map to be destroyed.
+
 */
+
void hashMapDestroy(HashMap *map);
+

+

+
#endif /* HASHMAP_H */
added external/libmachista/libmachista.c
@@ -0,0 +1,566 @@
+
/*
+
 * -*- coding: utf-8; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:filetype=c:et:sw=4:ts=4:sts=4:tw=100
+
 * libmachista.c
+
 * $Id: libmachista.c 120067 2014-05-14 22:18:53Z cal@macports.org $
+
 *
+
 * Copyright (c) 2011 The MacPorts Project
+
 * Copyright (c) 2011 Landon Fuller <landonf@macports.org>
+
 * Copyright (c) 2011 Clemens Lang <cal@macports.org>
+
 * All rights reserved.
+
 *
+
 * Redistribution and use in source and binary forms, with or without
+
 * modification, are permitted provided that the following conditions
+
 * are met:
+
 * 1. Redistributions of source code must retain the above copyright
+
 *    notice, this list of conditions and the following disclaimer.
+
 * 2. Redistributions in binary form must reproduce the above copyright
+
 *    notice, this list of conditions and the following disclaimer in the
+
 *    documentation and/or other materials provided with the distribution.
+
 * 
+
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+
 * POSSIBILITY OF SUCH DAMAGE.
+
 */
+

+
#ifdef HAVE_CONFIG_H
+
#include <pkg_config.h>
+
#endif
+

+
/* required for asprintf(3) on OS X */
+
#define _DARWIN_C_SOURCE
+
/* required for asprintf(3) on Linux */
+
#define _GNU_SOURCE
+

+
#include <stdbool.h>
+
#include <stdio.h>
+
#include <stdlib.h>
+

+
#include <fcntl.h>
+
#include <sys/mman.h>
+
#include <sys/stat.h>
+
#include <unistd.h>
+

+
#include <err.h>
+
#include <string.h>
+
#include <strings.h>
+

+
#ifdef __MACH__
+
#include <mach-o/fat.h>
+
#include <mach-o/loader.h>
+

+
#include <libkern/OSAtomic.h>
+
#endif
+

+
#include "libmachista.h"
+
#include "hashmap.h"
+

+
#ifdef __MACH__
+
/* Tiger compatibility */
+
#ifndef LC_RPATH
+
#define LC_RPATH       (0x1c | LC_REQ_DYLD)    /* runpath additions */
+
/*
+
 * The rpath_command contains a path which at runtime should be added to
+
 * the current run path used to find @rpath prefixed dylibs.
+
 */
+
struct rpath_command {
+
    uint32_t     cmd;       /* LC_RPATH */
+
    uint32_t     cmdsize;   /* includes string */
+
    union lc_str path;      /* path to add to run path */
+
};
+
#endif
+
#ifndef LC_REEXPORT_DYLIB
+
#define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) /* load and re-export dylib */
+
#endif
+
#endif /* __MACH__ */
+

+
typedef struct macho_input {
+
    const void *data;
+
    size_t length;
+
} macho_input_t;
+

+
/* This is macho_handle_t. The corresponding typedef is in the header */
+
struct macho_handle {
+
    HashMap *result_map;
+
};
+

+
#ifdef __MACH__
+
/* Verify that the given range is within bounds. */
+
static const void *macho_read (macho_input_t *input, const void *address, size_t length) {
+
    if ((((uint8_t *) address) - ((uint8_t *) input->data)) + length > input->length) {
+
       // warnx("Short read parsing Mach-O input");
+
        return NULL;
+
    }
+

+
    return address;
+
}
+

+
/* Verify that address + offset + length is within bounds. */
+
static const void *macho_offset (macho_input_t *input, const void *address, size_t offset, size_t length) {
+
    void *result = ((uint8_t *) address) + offset;
+
    return macho_read(input, result, length);
+
}
+
#endif
+

+
/* return a human readable formatted version number. the result must be free()'d. */
+
char *macho_format_dylib_version (uint32_t version) {
+
    char *result;
+
    asprintf(&result, "%"PRIu32".%"PRIu32".%"PRIu32, (version >> 16) & 0xFFFF, (version >> 8) & 0xFF, version & 0xFF);
+
    return result;
+
}
+

+
#ifdef __MACH__
+
const char *macho_get_arch_name (cpu_type_t cputype) {
+
    const NXArchInfo *archInfo = NXGetArchInfoFromCpuType(cputype, CPU_SUBTYPE_MULTIPLE);	
+
    if (!archInfo) {
+
        return NULL;
+
    }
+
    return archInfo->name;
+
#else
+
const char *macho_get_arch_name (cpu_type_t cputype UNUSED) {
+
    return NULL;
+
#endif
+
}
+

+
#ifdef __MACH__
+
/* Some byteswap wrappers */
+
static uint32_t macho_swap32 (uint32_t input) {
+
    return OSSwapInt32(input);
+
}
+

+
static uint32_t macho_nswap32(uint32_t input) {
+
    return input;
+
}
+

+
/* Creates a new macho_t.
+
 * Returns NULL on failure or a pointer to a 0-initialized macho_t on success */
+
static macho_t *create_macho_t (void) {
+
    macho_t *mt = malloc(sizeof(macho_t));
+
    if (mt == NULL)
+
        return NULL;
+

+
    memset(mt, 0, sizeof(macho_t));
+
    return mt;
+
}
+

+
/* Creates a new macho_arch_t.
+
 * Returns NULL on failure or a pointer to a 0-initialized macho_arch_t on success */
+
static macho_arch_t *create_macho_arch_t (void) {
+
    macho_arch_t *mat = malloc(sizeof(macho_arch_t));
+
    if (mat == NULL)
+
        return NULL;
+
    
+
    memset(mat, 0, sizeof(macho_arch_t));
+
    return mat;
+
}
+

+
/* Creates a new macho_loadcmd_t.
+
 * Returns NULL on failure or a pointer to a 0-initialized macho_loadcmd_t on success */
+
static macho_loadcmd_t *create_macho_loadcmd_t (void) {
+
    macho_loadcmd_t *mlt = malloc(sizeof(macho_loadcmd_t));
+
    if (mlt == NULL)
+
        return NULL;
+

+
    memset(mlt, 0, sizeof(macho_loadcmd_t));
+
    return mlt;
+
}
+
#endif
+

+
/* Frees a previously allocated macho_loadcmd_t and all it's associated resources */
+
static void free_macho_loadcmd_t (macho_loadcmd_t *mlt) {
+
    if (mlt == NULL)
+
        return;
+

+
    free(mlt->mlt_install_name);
+
    free(mlt);
+
}
+

+
/* Frees a previously allocated macho_arch_t and all it's associated resources */
+
static void free_macho_arch_t (macho_arch_t *mat) {
+
    if (mat == NULL)
+
        return;
+

+
    macho_loadcmd_t *current = mat->mat_loadcmds;
+
    while (current != NULL) {
+
        macho_loadcmd_t *freeme = current;
+
        current = current->next;
+
        free_macho_loadcmd_t(freeme);
+
    }
+

+
    free(mat->mat_install_name);
+
    free(mat->mat_rpath);
+
    free(mat);
+
}
+

+
/* Frees a previously allocated macho_t and all it's associated resources */
+
static void free_macho_t (macho_t *mt) {
+
    if (mt == NULL)
+
        return;
+

+
    macho_arch_t *current = mt->mt_archs;
+
    while (current != NULL) {
+
        macho_arch_t *freeme = current;
+
        current = current->next;
+
        free_macho_arch_t(freeme);
+
    }
+

+
    free(mt);
+
}
+

+
#ifdef __MACH__
+
/* Creates a new element in the architecture list of a macho_t (mt_archs), increases the counter of
+
 * architectures (mt_arch_count) and returns a pointer to the newly allocated element or NULL on
+
 * error */
+
static macho_arch_t *macho_archlist_append (macho_t *mt) {
+
    macho_arch_t *old_head = mt->mt_archs;
+

+
    macho_arch_t *new_head = create_macho_arch_t();
+
    if (new_head == NULL)
+
        return NULL;
+
    new_head->next = old_head;
+
    mt->mt_archs = new_head;
+

+
    return mt->mt_archs;
+
}
+

+
/* Creates a new element in the load command list of a macho_arch_t (mat_loadcmds), increases the
+
 * counter of load commands (mat_loadcmd_count) and returns a pointer to the newly allocated element
+
 * or NULL on error */
+
static macho_loadcmd_t *macho_loadcmdlist_append (macho_arch_t *mat) {
+
    macho_loadcmd_t *old_head = mat->mat_loadcmds;
+

+
    macho_loadcmd_t *new_head = create_macho_loadcmd_t();
+
    if (new_head == NULL)
+
        return NULL;
+
    new_head->next = old_head;
+
    mat->mat_loadcmds = new_head;
+

+
    return mat->mat_loadcmds;
+
}
+
#endif
+

+
/* Parse a Mach-O header */
+
#ifdef __MACH__
+
static int parse_macho (macho_t *mt, macho_input_t *input) {
+
    /* Read the file type. */
+
    const uint32_t *magic = macho_read(input, input->data, sizeof(uint32_t));
+
    if (magic == NULL)
+
        return MACHO_ERANGE;
+

+
    /* Parse the Mach-O header */
+
    bool universal = false;
+
    uint32_t (*swap32)(uint32_t) = macho_nswap32;
+

+
    const struct mach_header *header;
+
    const struct mach_header_64 *header64;
+
    size_t header_size;
+
    const struct fat_header *fat_header;
+

+
    macho_arch_t *mat = NULL;
+
    switch (*magic) {
+
        case MH_CIGAM:
+
            swap32 = macho_swap32;
+
            // Fall-through
+

+
        case MH_MAGIC:
+

+
            header_size = sizeof(*header);
+
            header = macho_read(input, input->data, header_size);
+
            if (header == NULL)
+
                return MACHO_ERANGE;
+
            mat = macho_archlist_append(mt);
+
            if (mat == NULL)
+
                return MACHO_EMEM;
+

+
            /* 32-bit Mach-O */
+
            mat->mat_arch = swap32(header->cputype);
+
            break;
+

+

+
        case MH_CIGAM_64:
+
            swap32 = macho_swap32;
+
            // Fall-through
+

+
        case MH_MAGIC_64:
+
            header_size = sizeof(*header64);
+
            header64 = macho_read(input, input->data, sizeof(*header64));
+
            if (header64 == NULL)
+
                return MACHO_ERANGE;
+
            mat = macho_archlist_append(mt);
+
            if (mat == NULL)
+
                return MACHO_EMEM;
+

+
            /* The 64-bit header is a direct superset of the 32-bit header */
+
            header = (struct mach_header *) header64;
+

+
            /* 64-bit Macho-O */
+
            mat->mat_arch = swap32(header->cputype);
+
            break;
+

+
        case FAT_CIGAM:
+
        case FAT_MAGIC:
+
            fat_header = macho_read(input, input->data, sizeof(*fat_header));
+
            universal = true;
+
            /* Universal binary */
+
            break;
+

+
        default:
+
            /* Unknown binary type */
+
            //warnx("Unknown Mach-O magic: 0x%" PRIx32 "", *magic);
+
            return MACHO_EMAGIC;
+
    }
+

+
    /* Parse universal file. */
+
    if (universal) {
+
        uint32_t nfat = OSSwapBigToHostInt32(fat_header->nfat_arch);
+
        const struct fat_arch *archs = macho_offset(input, fat_header, sizeof(struct fat_header), sizeof(struct fat_arch));
+
        if (archs == NULL)
+
            return MACHO_ERANGE;
+

+
        for (uint32_t i = 0; i < nfat; i++) { // foreach architecture
+
            const struct fat_arch *arch = macho_read(input, archs + i, sizeof(struct fat_arch));
+
            if (arch == NULL)
+
                return MACHO_ERANGE;
+

+
            /* Fetch a pointer to the architecture's Mach-O header. */
+
            macho_input_t arch_input;
+
            arch_input.length = OSSwapBigToHostInt32(arch->size);
+
            arch_input.data = macho_offset(input, input->data, OSSwapBigToHostInt32(arch->offset), arch_input.length);
+
            if (arch_input.data == NULL)
+
                return MACHO_ERANGE;
+

+
            /* Parse the architecture's Mach-O header */
+
            int res = parse_macho(mt, &arch_input);
+
            if (res != MACHO_SUCCESS)
+
                return res;
+
        }
+

+
        return MACHO_SUCCESS;
+
    }
+

+
    /* Copy the architecture */
+
    mat->mat_arch = swap32(header->cputype);
+

+
    /* Parse the Mach-O load commands */
+
    uint32_t ncmds = swap32(header->ncmds);
+

+
    /* Setup to jump over the header on the first pass through instead of the previous command */
+
    const struct load_command *cmd = (void *)header;
+
    uint32_t cmdsize = header_size;
+

+
    /* Iterate over the load commands */
+
    for (uint32_t i = 0; i < ncmds; i++) {
+
        /* Load the next command */
+
        cmd = macho_offset(input, cmd, cmdsize, sizeof(struct load_command));
+
        if (cmd == NULL)
+
            return MACHO_ERANGE;
+

+
        /* Load the full command */
+
        cmdsize = swap32(cmd->cmdsize);
+
        cmd = macho_read(input, cmd, cmdsize);
+
        if (cmd == NULL)
+
            return MACHO_ERANGE;
+

+
        /* Handle known types */
+
        uint32_t cmd_type = swap32(cmd->cmd);
+
        switch (cmd_type) {
+
            case LC_RPATH: {
+
                /* Copy the rpath */
+
                if (cmdsize < sizeof(struct rpath_command)) {
+
                    //warnx("Incorrect cmd size");
+
                    return MACHO_ERANGE;
+
                }
+

+
                size_t pathlen = cmdsize - sizeof(struct rpath_command);
+
                const void *pathptr = macho_offset(input, cmd, sizeof(struct rpath_command), pathlen);
+
                if (pathptr == NULL)
+
                    return MACHO_ERANGE;
+

+
                mat->mat_rpath = malloc(pathlen);
+
                if (mat->mat_rpath == NULL)
+
                    return MACHO_EMEM;
+
                strlcpy(mat->mat_rpath, pathptr, pathlen);
+
                break;
+
            }
+

+
            case LC_ID_DYLIB:
+
            case LC_LOAD_WEAK_DYLIB:
+
            case LC_REEXPORT_DYLIB:
+
            case LC_LOAD_DYLIB: {
+
                const struct dylib_command *dylib_cmd = (const struct dylib_command *) cmd;
+

+
                /* Extract the install name */
+
                if (cmdsize < sizeof(struct dylib_command)) {
+
                    //warnx("Incorrect name size");
+
                    return MACHO_ERANGE;
+
                }
+

+
                size_t namelen = cmdsize - sizeof(struct dylib_command);
+
                const void *nameptr = macho_offset(input, cmd, sizeof(struct dylib_command), namelen);
+
                if (nameptr == NULL)
+
                    return MACHO_ERANGE;
+

+
                if (cmd_type == LC_ID_DYLIB) {
+
                    /* Copy install name */
+
                    mat->mat_install_name = malloc(namelen);
+
                    if (mat->mat_install_name == NULL)
+
                        return MACHO_EMEM;
+
                    strlcpy(mat->mat_install_name, nameptr, namelen);
+

+
                    /* Copy version numbers (raw, for easier comparison) */
+
                    mat->mat_version = swap32(dylib_cmd->dylib.current_version);
+
                    mat->mat_comp_version = swap32(dylib_cmd->dylib.compatibility_version);
+
                } else {
+
                    /* Append loadcmd to list of loadcommands */
+
                    macho_loadcmd_t *mlt = macho_loadcmdlist_append(mat);
+
                    if (mlt == NULL)
+
                        return MACHO_EMEM;
+

+
                    /* Copy install name */
+
                    mlt->mlt_install_name = malloc(namelen);
+
                    if (mlt->mlt_install_name == NULL)
+
                        return MACHO_EMEM;
+
                    strlcpy(mlt->mlt_install_name, nameptr, namelen);
+

+
                    /* Copy version numbers (raw, for easier comparison) */
+
                    mlt->mlt_version = swap32(dylib_cmd->dylib.current_version);
+
                    mlt->mlt_comp_version = swap32(dylib_cmd->dylib.compatibility_version);
+

+
                    /* Copy command type */
+
                    mlt->mlt_type = cmd_type;
+
                }
+
                break;
+
            }
+

+
            default:
+
                break;
+
        }
+
    }
+

+
    return MACHO_SUCCESS;
+
}
+
#endif
+

+
/* Parse a (possible Mach-O) file. For a more detailed description, see the header */
+
#ifdef __MACH__
+
int macho_parse_file(macho_handle_t *handle, const char *filepath, const macho_t **res) {
+
    int fd;
+
    struct stat st;
+
    void *data;
+
    macho_input_t input_file;
+

+
    /* Check hashmap for precomputed results */
+
    const macho_t *cached_res = hashMapGet(handle->result_map, filepath);
+
    if (cached_res != NULL) {
+
        *res = cached_res;
+
        return MACHO_SUCCESS;
+
    }
+

+
    
+
    /* Open input file */
+
    if ((fd = open(filepath, O_RDONLY)) < 0) {
+
        return MACHO_EFILE;
+
    }
+

+
    /* Get file length */
+
    if (fstat(fd, &st) != 0) {
+
        close(fd);
+
        return MACHO_EFILE;
+
    }
+

+
    /* Map file into address space */
+
    if ((data = mmap(NULL, st.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
+
        close(fd);
+
        return MACHO_EMMAP;
+
    }
+

+
    /* Parse file */
+
    input_file.data = data;
+
    input_file.length = st.st_size;
+

+
    *res = create_macho_t();
+
    if (*res == NULL)
+
        return MACHO_EMEM;
+

+
    /* The output parameter *res should be read-only for the user of the lib only, but writable for
+
     * us */
+
    int ret = parse_macho((macho_t *)*res, &input_file);
+
    if (ret == MACHO_SUCCESS) {
+
        /* Insert into hashmap for caching */
+
        if (0 == hashMapPut(handle->result_map, filepath, *res, NULL)) {
+
            free_macho_t((macho_t *)*res);
+
            *res = NULL;
+
            ret = MACHO_EMEM;
+
        }
+
    } else {
+
        /* An error occured, free mt */
+
        free_macho_t((macho_t *)*res);
+
        *res = NULL;
+
    }
+

+
    /* Cleanup */
+
    munmap(data, st.st_size);
+
    close(fd);
+

+
    return ret;
+
#else
+
int macho_parse_file(macho_handle_t *handle UNUSED, const char *filepath UNUSED, const macho_t **res UNUSED) {
+
    return 0;
+
#endif
+
}
+

+
/* Create a new macho_handle_t. More information on this function is available in the header */
+
macho_handle_t *macho_create_handle (void) {
+
    macho_handle_t *mht = malloc(sizeof(macho_handle_t));
+
    if (mht == NULL)
+
        return NULL;
+
    mht->result_map = hashMapCreate((void (*)(const void *))free_macho_t);
+
    if (mht->result_map == NULL) {
+
        free(mht);
+
        return NULL;
+
    }
+
    return mht;
+
}
+

+
/* Release a macho_handle_t. For more documentation, see the header */
+
void macho_destroy_handle(macho_handle_t *handle) {
+
    if (handle == NULL)
+
        return;
+
    
+
    hashMapDestroy(handle->result_map);
+

+
    free(handle);
+
}
+

+
/* Returns string representation of the MACHO_* error code constants */
+
const char *macho_strerror(int err) {
+
    int num;
+
#ifdef HAVE_FLS
+
    num = fls(err);
+
#else
+
    /* Tiger compatibility, see #42186 */
+
    num = 0;
+
    while (err > 0) {
+
        err >>= 1;
+
        num++;
+
    }
+
#endif
+

+
    static char *errors[] = {
+
        /* 0x00 */ "Success",
+
        /* 0x01 */ "Error opening or reading file",
+
        /* 0x02 */ "Error mapping file into memory",
+
        /* 0x04 */ "Error allocating memory",
+
        /* 0x08 */ "Premature end of data, possibly corrupt file",
+
        /* 0x10 */ "Not a Mach-O file",
+
    };
+
    return errors[num];
+
}
+

added external/libmachista/libmachista.h
@@ -0,0 +1,148 @@
+
/*
+
 * -*- coding: utf-8; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:filetype=c:et:sw=4:ts=4:sts=4:tw=100
+
 * libmachista.h
+
 * $Id$
+
 *
+
 * Copyright (c) 2011 The MacPorts Project
+
 * Copyright (c) 2011 Clemens Lang <cal@macports.org>
+
 * All rights reserved.
+
 *
+
 * Redistribution and use in source and binary forms, with or without
+
 * modification, are permitted provided that the following conditions
+
 * are met:
+
 * 1. Redistributions of source code must retain the above copyright
+
 *    notice, this list of conditions and the following disclaimer.
+
 * 2. Redistributions in binary form must reproduce the above copyright
+
 *    notice, this list of conditions and the following disclaimer in the
+
 *    documentation and/or other materials provided with the distribution.
+
 *
+
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+
 * POSSIBILITY OF SUCH DAMAGE.
+
 */
+

+
#ifndef __LIBMACHISTA_H__
+
#define __LIBMACHISTA_H__
+

+
/*
+
 * This is a library to parse Mach-O files in single architecture _and_ universal variant and return
+
 * a list of architectures and their load commands and properties
+
 * The name a pun: machista is the spanish translation of "macho".
+
 */
+

+
#ifdef __MACH__
+
#include <mach-o/arch.h>
+
#else
+
typedef int cpu_type_t;
+
#endif
+
#include <inttypes.h>
+

+
#define MACHO_SUCCESS   (0x00)
+
#define MACHO_EFILE     (0x01)
+
#define MACHO_EMMAP     (0x02)
+
#define MACHO_EMEM      (0x04)
+
#define MACHO_ERANGE    (0x08)
+
#define MACHO_EMAGIC    (0x10)
+

+
/* Blind structure; this essentially contains the hash map used to cache
+
 * entries, but users should not have to look into this structure. struct
+
 * macho_handle is defined in libmachista.c */
+
typedef struct macho_handle macho_handle_t;
+

+
/** Structure describing a load command within a Mach-O file */
+
typedef struct macho_loadcmd {
+
    char *mlt_install_name;         /* install name of the library to be loaded by this load command */
+
    uint32_t mlt_type;              /* type of the load command; see mach-o/loader.h for possible
+
                                       values */
+
    uint32_t mlt_comp_version;      /* compatibility version of the file to be loaded by this
+
                                       command (at build time of this file) */
+
    uint32_t mlt_version;           /* version of the library to be loaded by this command (at build
+
                                       time of this file) */
+
    struct macho_loadcmd *next;     /* pointer to the next entry in the linked list of
+
                                       macho_loadcmd_t's (NULL if there's no further element) */
+
} macho_loadcmd_t;
+

+
/** Stucture describing an architecture within a Mach-O file */
+
typedef struct macho_arch {
+
    char *mat_install_name;         /* install name of the library or NULL if none */
+
    char *mat_rpath;                /* rpath of the binary of NULL if none */
+
    cpu_type_t mat_arch;            /* cpu_type_t describing the CPU this part of the binary is
+
                                       intended for */
+
    uint32_t mat_comp_version;      /* compatibility version of this part of the binary */
+
    uint32_t mat_version;           /* current version of this part of the binary */
+
    macho_loadcmd_t *mat_loadcmds;  /* array of macho_loadcmd_t's describing the different load
+
                                       commands */
+
    struct macho_arch *next;        /* pointer to the next entry in the linked list of
+
                                       macho_arch_t's (NULL if there's no further element) */
+
} macho_arch_t;
+

+
/** Structure describing a Mach-O file */
+
typedef struct macho {
+
    macho_arch_t *mt_archs;         /* linked list of macho_arch_t's describing the different
+
                                       architectures */
+
} macho_t;
+

+
/**
+
 * Creates and returns a macho_handle_t to be passed to subsequent calls to macho_parse_file. No
+
 * assumptions should be made about the contents of a macho_handle_t; it is declared to be a blind
+
 * structure.
+
 *
+
 * Returns either a pointer to a valid macho_handle_t or NULL on failure. errno will be set on
+
 * failure. The resources associated with a macho_handle_t must be freed by passing it to
+
 * macho_destroy_handle.
+
 */
+
macho_handle_t *macho_create_handle(void);
+

+
/**
+
 * Frees resources associated with a macho_handle_t and invalidates all results returned by
+
 * macho_parse_file called with this handle.
+
 */
+
void macho_destroy_handle(macho_handle_t *handle);
+

+
/**
+
 * Formats a dylib version number given by an uint32_t into a human-readable format and returns a
+
 * Pointer to the beginning of that string. The result is either a valid pointer or NULL on error
+
 * (in which case the errno is set to indicate the error). The pointer must be free()'d after use.
+
 */
+
char *macho_format_dylib_version(uint32_t version);
+

+
/**
+
 * Returns a readable version of any cpu_type_t constant. Returns a valid pointer to the first
+
 * character in a 0-terminated string or NULL on error. The pointer must not be free()'d after use.
+
 */
+
const char *macho_get_arch_name(cpu_type_t cputype);
+

+
/**
+
 * Parses the Mach-O file indicated by filepath and writes a pointer to a macho_t describing the
+
 * Mach-O file into the location idicated by res. Returns MACHO_SUCCESS on success or any of the
+
 * following error codes on error:
+
 *
+
 * code             description                                     errno set?
+
 * MACHO_EFILE      error stat()'ing, opening or reading the file   yes
+
 * MACHO_EMMAP      error mmap()'ing the file                       yes
+
 * MACHO_EMEM       error allocating memory                         yes
+
 * MACHO_ERANGE     unexpected end of file                          no
+
 * MACHO_EMAGIC     unknown magic number/not a Mach-O file          no
+
 *
+
 * On error, the contents of res are undefined and should not be used. The memory associated with
+
 * the result *res will be free()'d and should thus not be used after calling macho_destroy_handle
+
 * on the macho_handle_t used for the call. *res should also never be modified or otherwise
+
 * free()'d.
+
 */
+
int macho_parse_file(macho_handle_t *handle, const char *filepath, const macho_t **res);
+

+
/**
+
 * Returns a string representation of the MACHO_* error code constants
+
 */
+
const char *macho_strerror(int err);
+

+
#endif
+

modified libpkg/Makefile.am
@@ -66,6 +66,7 @@ endif

if HAVE_MACHO_ABI
libpkg_la_SOURCES+=	pkg_macho.c
+
pkg_common_cflags+=	-I$(top_srcdir)/external/libmachista
endif

libpkg_la_CFLAGS=	$(pkg_common_cflags) -shared
@@ -93,6 +94,10 @@ libpkg_la_LIBADD+= -lelf
endif
endif

+
if HAVE_MACHO_ABI
+
libpkg_la_LIBADD+=	$(top_builddir)/external/libmachista_static.la
+
endif
+

libpkg_la_LDFLAGS=	-version-info @LIBPKG_SO_VERSION@
EXTRA_libpkg_la_DEPENDENCIES=	@REPOS_LDADD@