Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

1494 lines (1266 sloc) 43.784 kB
/*
* Copyright (c) 2008-2011, 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. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
*/
#if !defined(MACRUBY_STATIC)
#include "bs.h"
#include <libxml/xmlreader.h>
#include <dlfcn.h>
#include <libgen.h>
#include <unistd.h>
#include "bs_lex.h"
#define ASSERT_ALLOC(ptr) (assert(ptr != NULL))
static inline char *
get_framework_name(const char *path)
{
char *base;
char *name;
char *p;
base = basename((char *)path);
if (base == NULL)
return NULL;
p = strrchr(base, '.');
if (p == NULL)
return NULL;
if (strcmp(p + 1, "framework") != 0)
return NULL;
assert(p - base > 0);
name = (char *)malloc(p - base + 1);
ASSERT_ALLOC(name);
strncpy(name, base, p - base);
name[p - base] = '\0';
return name;
}
static inline const char *
_bs_main_bundle_bs_path(void)
{
static bool done = false;
static char *path = NULL;
/* XXX not thread-safe */
if (!done) {
CFBundleRef bundle;
done = true;
bundle = CFBundleGetMainBundle();
if (bundle != NULL) {
CFURLRef url;
url = CFBundleCopyResourceURL(bundle, CFSTR("BridgeSupport"),
NULL, NULL);
if (url != NULL) {
CFStringRef str = CFURLCopyPath(url);
path = (char *)malloc(sizeof(char) * PATH_MAX);
ASSERT_ALLOC(path);
CFStringGetFileSystemRepresentation(str, path, PATH_MAX);
CFRelease(str);
CFRelease(url);
}
}
}
return path;
}
static bool
_bs_find_path(const char *framework_path, char *path, const size_t path_len,
const char *ext)
{
const char *main_bundle_bs_path;
char *framework_name;
char *home;
if (framework_path == NULL || *framework_path == '\0'
|| path == NULL || path_len == 0)
return false;
#define CHECK_IF_EXISTS() \
do { \
if (access(path, R_OK) == 0) { \
free(framework_name); \
return true; \
} \
} \
while (0)
framework_name = get_framework_name(framework_path);
if (framework_name == NULL)
return false;
main_bundle_bs_path = _bs_main_bundle_bs_path();
if (main_bundle_bs_path != NULL) {
snprintf(path, path_len, "%s/%s.%s", main_bundle_bs_path,
framework_name, ext);
CHECK_IF_EXISTS();
}
snprintf(path, path_len, "%s/Resources/BridgeSupport/%s.%s",
framework_path, framework_name, ext);
CHECK_IF_EXISTS();
home = getenv("HOME");
if (home != NULL) {
snprintf(path, path_len, "%s/Library/BridgeSupport/%s.%s",
home, framework_name, ext);
CHECK_IF_EXISTS();
}
snprintf(path, path_len, "/Library/BridgeSupport/%s.%s",
framework_name, ext);
CHECK_IF_EXISTS();
snprintf(path, path_len, "/System/Library/BridgeSupport/%s.%s",
framework_name, ext);
CHECK_IF_EXISTS();
#undef CHECK_IF_EXISTS
free(framework_name);
return false;
}
bool
bs_find_path(const char *framework_path, char *path, const size_t path_len)
{
return _bs_find_path(framework_path, path, path_len, "bridgesupport");
}
static inline char *
get_attribute(xmlTextReaderPtr reader, const char *name)
{
return (char *)xmlTextReaderGetAttribute(reader, (const xmlChar *)name);
}
static inline char *
get_type64_attribute(xmlTextReaderPtr reader)
{
return (char *)xmlTextReaderGetAttribute(reader, (xmlChar *)"type64");
}
static inline char *
get_type_attribute(xmlTextReaderPtr reader)
{
#if __LP64__
char *value = get_type64_attribute(reader);
if (value != NULL)
return value;
#endif
return (char *)xmlTextReaderGetAttribute(reader, (xmlChar *)"type");
}
static void
get_c_ary_type_attribute(xmlTextReaderPtr reader, bs_carray_arg_type_t *type,
int *value)
{
char *c_ary_type;
if ((c_ary_type = get_attribute(reader, "c_array_length_in_arg")) != NULL) {
*type = BS_CARRAY_ARG_LENGTH_IN_ARG;
*value = atoi(c_ary_type);
}
else if ((c_ary_type = get_attribute(reader, "c_array_of_fixed_length"))
!= NULL) {
*type = BS_CARRAY_ARG_FIXED_LENGTH;
*value = atoi(c_ary_type);
}
else if ((c_ary_type = get_attribute(reader, "c_array_of_variable_length"))
!= NULL && strcmp(c_ary_type, "true") == 0) {
*type = BS_CARRAY_ARG_VARIABLE_LENGTH;
*value = -1;
}
else if ((c_ary_type = get_attribute(reader, "c_array_delimited_by_null"))
!= NULL && strcmp(c_ary_type, "true") == 0) {
*type = BS_CARRAY_ARG_DELIMITED_BY_NULL;
*value = -1;
}
else {
*type = BS_CARRAY_ARG_UNDEFINED;
*value = -1;
}
if (c_ary_type != NULL)
free(c_ary_type);
}
static void
get_type_modifier_attribute(xmlTextReaderPtr reader, bs_type_modifier_t *type)
{
char *type_modifier = get_attribute(reader, "type_modifier");
*type = BS_TYPE_MODIFIER_UNDEFINED;
if (type_modifier != NULL && strlen(type_modifier) == 1) {
switch (*type_modifier) {
case 'n':
*type = BS_TYPE_MODIFIER_IN;
break;
case 'o':
*type = BS_TYPE_MODIFIER_OUT;
break;
case 'N':
*type = BS_TYPE_MODIFIER_INOUT;
break;
}
}
free(type_modifier);
}
static inline bool
get_boolean_attribute(xmlTextReaderPtr reader, const char *name,
bool default_value)
{
char *value;
bool ret;
value = get_attribute(reader, name);
if (value == NULL)
return default_value;
ret = strcmp(value, "true") == 0;
free(value);
return ret;
}
#define MAX_ENCODE_LEN 4096
#ifndef MIN
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
static bool
undecorate_struct_type(const char *src, char *dest, size_t dest_len,
bs_element_struct_field_t *fields,
size_t fields_count, int *out_fields_count)
{
const char *p_src;
char *p_dst;
char *pos;
size_t src_len;
unsigned field_idx;
unsigned i;
p_src = src;
p_dst = dest;
src_len = strlen(src);
field_idx = 0;
if (out_fields_count != NULL)
*out_fields_count = 0;
for (;;) {
bs_element_struct_field_t *field;
size_t len;
field = field_idx < fields_count ? &fields[field_idx] : NULL;
/* Locate the first field, if any. */
pos = strchr(p_src, '"');
/* Copy what's before the first field, or the rest of the source. */
len = MIN(pos == NULL ? src_len - (p_src - src) + 1 : pos - p_src, dest_len - (p_dst - dest));
strncpy(p_dst, p_src, len);
p_dst += len;
/* We can break if there wasn't any field. */
if (pos == NULL)
break;
/* Jump to the end of the field, saving the field name if necessary. */
p_src = pos + 1;
pos = strchr(p_src, '"');
if (pos == NULL) {
fprintf(stderr, "Can't find the end of field delimiter starting at %d\n", (int)(p_src - src));
goto bails;
}
if (field != NULL) {
field->name = (char *)malloc((sizeof(char) * (pos - p_src)) + 1);
ASSERT_ALLOC(field->name);
strncpy(field->name, p_src, pos - p_src);
field->name[pos - p_src] = '\0';
field_idx++;
}
p_src = pos + 1;
pos = NULL;
/* Save the field encoding if necessary. */
if (field != NULL) {
char opposite;
bool ok;
int nested;
opposite =
*p_src == '{' ? '}' :
*p_src == '(' ? ')' :
*p_src == '[' ? ']' : 0;
for (i = 0, ok = false, nested = 0;
i < src_len - (p_src - src) && !ok;
i++) {
char c = p_src[i];
if (opposite != 0) {
/* Encoding is a structure, we need to match the closing '}',
* taking into account that other structures can be nested in it.
*/
if (c == opposite) {
if (nested == 0)
ok = true;
else
nested--;
}
else if (c == *p_src && i > 0)
nested++;
}
else {
/* Easy case, just match another field delimiter, or the end
* of the encoding.
*/
if (c == '"' || c == '}') {
i--;
ok = true;
}
}
}
if (ok == false) {
fprintf(stderr, "Can't find the field encoding starting at %d\n", (int)(p_src - src));
goto bails;
}
if (opposite == '}' || opposite == ')') {
char buf[MAX_ENCODE_LEN];
char buf2[MAX_ENCODE_LEN];
strncpy(buf, p_src, MIN(sizeof buf, i));
buf[MIN(sizeof buf, i)] = '\0';
if (!undecorate_struct_type(buf, buf2, sizeof buf2, NULL, 0, NULL)) {
fprintf(stderr, "Can't un-decode the field encoding '%s'\n", buf);
goto bails;
}
len = strlen(buf2);
field->type = (char *)malloc((sizeof(char) * len) + 1);
ASSERT_ALLOC(field->type);
strncpy(field->type, buf2, len);
field->type[len] = '\0';
}
else {
field->type = (char *)malloc((sizeof(char) * i) + 1);
ASSERT_ALLOC(field->type);
strncpy(field->type, p_src, i);
field->type[i] = '\0';
len = i;
}
strncpy(p_dst, field->type, len);
p_src += i;
p_dst += len;
}
}
*p_dst = '\0';
if (out_fields_count != NULL)
*out_fields_count = field_idx;
return true;
bails:
/* Free what we allocated! */
for (i = 0; i < field_idx; i++) {
free(fields[i].name);
free(fields[i].type);
}
return false;
}
struct _bs_parser {
unsigned int version_number;
CFMutableArrayRef loaded_paths;
};
bs_parser_t *
bs_parser_new(void)
{
struct _bs_parser *parser;
parser = (struct _bs_parser *)malloc(sizeof(struct _bs_parser));
ASSERT_ALLOC(parser);
parser->loaded_paths =
CFArrayCreateMutable(kCFAllocatorMalloc, 0, &kCFTypeArrayCallBacks);
return parser;
}
void
bs_parser_free(bs_parser_t *parser)
{
CFRelease(parser->loaded_paths);
free(parser);
}
bool
bs_parser_parse(bs_parser_t *parser, const char *path,
const char *framework_path, bs_parse_options_t options,
bs_parse_callback_t callback, void *context, char **error)
{
xmlTextReaderPtr reader;
bs_element_function_t *func;
bs_element_class_t *klass;
bs_element_method_t *method;
unsigned int i;
#define MAX_ARGS 128
bs_element_arg_t args[MAX_ARGS];
bs_element_arg_t fptr_args[MAX_ARGS];
char *protocol_name = NULL;
int func_ptr_arg_depth;
bs_element_function_pointer_t *func_ptr;
bool success;
CFStringRef cf_path;
bool nested_func_ptr;
unsigned int version_number = 0;
if (callback == NULL)
return false;
/* check if the given framework path has not been loaded already */
cf_path = CFStringCreateWithFileSystemRepresentation(kCFAllocatorMalloc,
path);
CFMakeCollectable(cf_path);
for (unsigned i = 0, count = CFArrayGetCount(parser->loaded_paths);
i < count; i++) {
CFStringRef s = CFArrayGetValueAtIndex(parser->loaded_paths, i);
if (CFStringCompare(cf_path, s, kCFCompareCaseInsensitive)
== kCFCompareEqualTo) {
/* already loaded */
return true;
}
}
CFArrayAppendValue(parser->loaded_paths, cf_path);
//printf("parsing %s\n", path);
#define BAIL(fmt, args...) \
do { \
if (error != NULL) { \
char buf[1024]; \
snprintf(buf, sizeof buf, \
"%s:%ld - "fmt, path, \
xmlGetLineNo(xmlTextReaderCurrentNode(reader)), \
##args); \
*error = strdup(buf); \
} \
success = false; \
goto bails; \
} \
while (0)
#if __LP64__
# define CHECK_TYPE_ATTRIBUTE(var) CHECK_ATTRIBUTE(var, "type")
#else
# define CHECK_TYPE_ATTRIBUTE(var) \
if (var == NULL && get_type64_attribute(reader) != NULL) { \
break; \
} \
CHECK_ATTRIBUTE(var, "type")
#endif
#define CHECK_ATTRIBUTE_CAN_BE_EMPTY(a, name) \
CHECK_ATTRIBUTE0(a, name, true)
#define CHECK_ATTRIBUTE(a, name) \
CHECK_ATTRIBUTE0(a, name, false)
#define CHECK_ATTRIBUTE0(a, name, can_be_empty) \
do { \
if (a == NULL) \
BAIL("expected attribute `%s' for element `%s'", \
name, xmlTextReaderConstName(reader)); \
if (!can_be_empty && *a == '\0') { \
free(a); \
BAIL("empty attribute `%s' for element `%s'", \
name, xmlTextReaderConstName(reader)); \
} \
} while (0) \
reader = xmlNewTextReaderFilename(path);
if (reader == NULL)
BAIL("cannot create XML text reader for file at path `%s'", path);
func = NULL;
func_ptr = NULL;
func_ptr_arg_depth = -1;
nested_func_ptr = false;
klass = NULL;
method = NULL;
protocol_name = NULL;
while (true) {
const char *name;
unsigned int namelen;
int node_type = -1;
bool eof = false;
struct bs_xml_atom *atom;
void *bs_element;
bs_element_type_t bs_element_type = 0;
do {
int retval = xmlTextReaderRead(reader);
if (retval == 0) {
eof = true;
break;
}
else if (retval < 0)
BAIL("parsing error: %d", retval);
node_type = xmlTextReaderNodeType(reader);
}
while (node_type != XML_READER_TYPE_ELEMENT
&& node_type != XML_READER_TYPE_END_ELEMENT);
if (eof)
break;
name = (const char *)xmlTextReaderConstName(reader);
namelen = strlen(name);
bs_element = NULL;
atom = bs_xml_element(name, namelen);
if (atom == NULL) {
// TODO: we should include the "signatures" string into the gperf
// function.
if (version_number == 0 && strcmp(name, "signatures") == 0) {
char *str = get_attribute(reader, "version");
if (str != NULL) {
char *p = strchr(str, '.');
if (p != NULL) {
*p = '\0';
int major = atoi(str);
int minor = atoi(&p[1]);
assert(major < 10 && minor < 10);
version_number = (major * 10) + minor;
parser->version_number = version_number;
}
free(str);
}
}
continue;
}
if (nested_func_ptr) {
// FIXME: elements nesting function_pointers aren't supported yet by the
// parser, so we just ignore them.
if (node_type == XML_READER_TYPE_END_ELEMENT
&& (atom->val == BS_XML_FUNCTION || atom->val == BS_XML_METHOD)) {
nested_func_ptr = false;
}
continue;
}
if (node_type == XML_READER_TYPE_ELEMENT) {
switch (atom->val) {
case BS_XML_DEPENDS_ON:
{
char *depends_on_path;
char bs_path[PATH_MAX];
bool bs_path_found;
depends_on_path = get_attribute(reader, "path");
CHECK_ATTRIBUTE(depends_on_path, "path");
//printf("depends of %s\n", depends_on_path);
bs_path_found = bs_find_path(depends_on_path, bs_path,
sizeof bs_path);
if (bs_path_found) {
if (!bs_parser_parse(parser, bs_path, depends_on_path, options,
callback, context, error)) {
free(depends_on_path);
return false;
}
}
free(depends_on_path);
break;
}
case BS_XML_CONSTANT:
{
bs_element_constant_t *bs_const;
char *const_name;
char *const_type;
const_name = get_attribute(reader, "name");
CHECK_ATTRIBUTE(const_name, "name");
const_type = get_type_attribute(reader);
CHECK_TYPE_ATTRIBUTE(const_type);
bs_const = (bs_element_constant_t *)
malloc(sizeof(bs_element_constant_t));
ASSERT_ALLOC(bs_const);
bs_const->name = const_name;
bs_const->type = const_type;
bs_const->ignore = false;
bs_const->suggestion = NULL;
bs_const->magic_cookie = get_boolean_attribute(reader,
"magic_cookie", false);
bs_element = bs_const;
bs_element_type = BS_ELEMENT_CONSTANT;
break;
}
case BS_XML_STRING_CONSTANT:
{
bs_element_string_constant_t *bs_strconst;
char *strconst_name;
char *strconst_value;
strconst_name = get_attribute(reader, "name");
CHECK_ATTRIBUTE(strconst_name, "name");
strconst_value = get_attribute(reader, "value");
CHECK_ATTRIBUTE_CAN_BE_EMPTY(strconst_value, "value");
bs_strconst = (bs_element_string_constant_t *)
malloc(sizeof(bs_element_string_constant_t));
ASSERT_ALLOC(bs_strconst);
bs_strconst->name = strconst_name;
bs_strconst->value = strconst_value;
bs_strconst->nsstring = get_boolean_attribute(reader, "nsstring",
false);
bs_element = bs_strconst;
bs_element_type = BS_ELEMENT_STRING_CONSTANT;
break;
}
case BS_XML_ENUM:
{
char *enum_name;
char *enum_value;
enum_name = get_attribute(reader, "name");
CHECK_ATTRIBUTE(enum_name, "name");
#if __LP64__
enum_value = get_attribute(reader, "value64");
if (enum_value == NULL)
#endif
enum_value = get_attribute(reader, "value");
#if BYTE_ORDER == BIG_ENDIAN
# define BYTE_ORDER_VALUE_ATTR_NAME "be_value"
#else
# define BYTE_ORDER_VALUE_ATTR_NAME "le_value"
#endif
if (enum_value == NULL)
enum_value = get_attribute(reader, BYTE_ORDER_VALUE_ATTR_NAME);
if (enum_value != NULL) {
bs_element_enum_t *bs_enum;
bs_enum = (bs_element_enum_t *)malloc(sizeof(bs_element_enum_t));
ASSERT_ALLOC(bs_enum);
bs_enum->name = enum_name;
bs_enum->value = enum_value;
bs_enum->ignore = get_boolean_attribute(reader, "ignore", false);
bs_enum->suggestion = get_attribute(reader, "suggestion");
bs_element = bs_enum;
bs_element_type = BS_ELEMENT_ENUM;
}
break;
}
case BS_XML_STRUCT:
{
bs_element_struct_t *bs_struct;
char *struct_decorated_type;
char *struct_name;
char type[MAX_ENCODE_LEN];
bs_element_struct_field_t fields[128];
int field_count;
struct_decorated_type = get_type_attribute(reader);
CHECK_TYPE_ATTRIBUTE(struct_decorated_type);
struct_name = get_attribute(reader, "name");
CHECK_ATTRIBUTE(struct_name, "name");
if (!undecorate_struct_type(struct_decorated_type, type,
sizeof type, fields, 128,
&field_count)) {
BAIL("Can't handle structure '%s' with type '%s'",
struct_name, struct_decorated_type);
}
free(struct_decorated_type);
bs_struct =
(bs_element_struct_t *)malloc(sizeof(bs_element_struct_t));
ASSERT_ALLOC(bs_struct);
bs_struct->name = struct_name;
bs_struct->type = strdup(type);
bs_struct->fields = (bs_element_struct_field_t *)malloc(
sizeof(bs_element_struct_field_t) * field_count);
ASSERT_ALLOC(bs_struct->fields);
memcpy(bs_struct->fields, fields,
sizeof(bs_element_struct_field_t) * field_count);
bs_struct->fields_count = field_count;
bs_struct->opaque = get_boolean_attribute(reader, "opaque", false);
bs_element = bs_struct;
bs_element_type = BS_ELEMENT_STRUCT;
break;
}
case BS_XML_OPAQUE:
{
bs_element_opaque_t *bs_opaque;
char *opaque_name;
char *opaque_type;
opaque_name = get_attribute(reader, "name");
CHECK_ATTRIBUTE(opaque_name, "name");
opaque_type = get_type_attribute(reader);
CHECK_TYPE_ATTRIBUTE(opaque_type);
bs_opaque =
(bs_element_opaque_t *)malloc(sizeof(bs_element_opaque_t));
ASSERT_ALLOC(bs_opaque);
bs_opaque->name = opaque_name;
bs_opaque->type = opaque_type;
bs_element = bs_opaque;
bs_element_type = BS_ELEMENT_OPAQUE;
break;
}
case BS_XML_CFTYPE:
{
bs_element_cftype_t *bs_cftype;
char *cftype_name;
char *cftype_type;
cftype_name = get_attribute(reader, "name");
CHECK_ATTRIBUTE(cftype_name, "name");
cftype_type = get_type_attribute(reader);
CHECK_TYPE_ATTRIBUTE(cftype_type);
bs_cftype =
(bs_element_cftype_t *)malloc(sizeof(bs_element_cftype_t));
ASSERT_ALLOC(bs_cftype);
bs_cftype->name = cftype_name;
bs_cftype->type = cftype_type;
#if 1
/* the type_id field isn't used in MacRuby */
bs_cftype->type_id = 0;
#else
char *cftype_gettypeid_func_name;
cftype_gettypeid_func_name = get_attribute(reader, "gettypeid_func");
if (cftype_gettypeid_func_name != NULL) {
void *sym;
sym = dlsym(RTLD_DEFAULT, cftype_gettypeid_func_name);
if (sym == NULL) {
BAIL("cannot locate gettypeid_func function `%s'",
cftype_gettypeid_func_name);
}
else {
CFTypeID (*cb)(void) = sym;
bs_cftype->type_id = (*cb)();
}
}
else {
bs_cftype->type_id = 0;
}
#endif
bs_cftype->tollfree = get_attribute(reader, "tollfree");
bs_element = bs_cftype;
bs_element_type = BS_ELEMENT_CFTYPE;
break;
}
case BS_XML_INFORMAL_PROTOCOL:
{
if (protocol_name != NULL)
free(protocol_name);
protocol_name = get_attribute(reader, "name");
CHECK_ATTRIBUTE(protocol_name, "name");
break;
}
case BS_XML_FUNCTION:
{
char *func_name;
func_name = get_attribute(reader, "name");
CHECK_ATTRIBUTE(func_name, "name");
func =
(bs_element_function_t *)malloc(sizeof(bs_element_function_t));
ASSERT_ALLOC(func);
func->name = func_name;
func->variadic = get_boolean_attribute(reader, "variadic", false);
func->args_count = 0;
func->args = NULL;
func->retval = NULL;
if (xmlTextReaderIsEmptyElement(reader)) {
bs_element = func;
bs_element_type = BS_ELEMENT_FUNCTION;
func = NULL;
}
break;
}
case BS_XML_FUNCTION_ALIAS:
{
bs_element_function_alias_t *bs_func_alias;
char *alias_name;
char *alias_original;
alias_name = get_attribute(reader, "name");
CHECK_ATTRIBUTE(alias_name, "name");
alias_original = get_attribute(reader, "original");
CHECK_ATTRIBUTE(alias_original, "original");
bs_func_alias = (bs_element_function_alias_t *)malloc(
sizeof(bs_element_function_alias_t));
ASSERT_ALLOC(bs_func_alias);
bs_func_alias->name = alias_name;
bs_func_alias->original = alias_original;
bs_element = bs_func_alias;
bs_element_type = BS_ELEMENT_FUNCTION_ALIAS;
break;
}
case BS_XML_CLASS:
{
char *class_name;
class_name = get_attribute(reader, "name");
CHECK_ATTRIBUTE(class_name, "name");
klass = (bs_element_class_t *)malloc(sizeof(bs_element_class_t));
ASSERT_ALLOC(klass);
klass->name = class_name;
klass->class_methods = klass->instance_methods = NULL;
klass->class_methods_count = klass->instance_methods_count = 0;
break;
}
case BS_XML_ARG:
{
if (func != NULL || method != NULL || func_ptr != NULL) {
bs_element_arg_t *bs_arg;
unsigned *argc;
argc = func_ptr != NULL
? &func_ptr->args_count
: func != NULL
? &func->args_count
: &method->args_count;
if (*argc >= MAX_ARGS) {
if (func_ptr != NULL)
BAIL("maximum number of arguments (%d) reached " \
"for function pointer", MAX_ARGS);
else if (func != NULL)
BAIL("maximum number of arguments (%d) reached " \
"for function '%s'", MAX_ARGS, func->name);
else
BAIL("maximum number of arguments (%d) reached " \
"for method '%s'", MAX_ARGS, (char *)method->name);
}
bs_element_arg_t *args_from =
(func_ptr == NULL ? args : fptr_args);
bs_arg = &args_from[(*argc)++];
if (method != NULL && func_ptr == NULL) {
char *index = get_attribute(reader, "index");
CHECK_ATTRIBUTE(index, "index");
bs_arg->index = strtol(index, NULL, 10);
free(index);
}
else {
bs_arg->index = -1;
}
get_type_modifier_attribute(reader, &bs_arg->type_modifier);
#if __LP64__
bs_arg->sel_of_type = get_attribute(reader, "sel_of_type64");
if (bs_arg->sel_of_type == NULL)
#endif
bs_arg->sel_of_type = get_attribute(reader, "sel_of_type");
bs_arg->printf_format = get_boolean_attribute(reader,
"printf_format", false);
bs_arg->null_accepted = get_boolean_attribute(reader,
"null_accepted", true);
get_c_ary_type_attribute(reader,
&bs_arg->carray_type, &bs_arg->carray_type_value);
bs_arg->type = get_type_attribute(reader);
if (get_boolean_attribute(reader, "function_pointer", false)) {
if (func_ptr != NULL) {
func_ptr = NULL;
nested_func_ptr = true;
break;
}
bs_arg->function_pointer = (bs_element_function_pointer_t *)
calloc(1, sizeof(bs_element_function_pointer_t));
ASSERT_ALLOC(bs_arg->function_pointer);
func_ptr = bs_arg->function_pointer;
func_ptr_arg_depth = xmlTextReaderDepth(reader);
}
else {
bs_arg->function_pointer = NULL;
}
}
else {
BAIL("argument defined outside of a " \
"function/method/function_pointer");
}
break;
}
case BS_XML_RETVAL:
{
if (func != NULL || method != NULL || func_ptr != NULL) {
bs_element_retval_t *bs_retval;
if (func_ptr != NULL) {
if (func_ptr->retval != NULL)
BAIL("function pointer return value defined more than once");
}
else if (func != NULL) {
if (func->retval != NULL)
BAIL("function '%s' return value defined more than once",
func->name);
}
else if (method != NULL) {
if (method->retval != NULL)
BAIL("method '%s' return value defined more than once",
(char *)method->name);
}
bs_retval =
(bs_element_retval_t *)malloc(sizeof(bs_element_retval_t));
ASSERT_ALLOC(bs_retval);
get_c_ary_type_attribute(reader, &bs_retval->carray_type,
&bs_retval->carray_type_value);
bs_retval->type = get_type_attribute(reader);
if (bs_retval->type != NULL)
bs_retval->already_retained =
get_boolean_attribute(reader, "already_retained", false);
if (func_ptr != NULL) {
if (bs_retval->type != NULL) {
func_ptr->retval = bs_retval;
}
else {
free(bs_retval);
BAIL("function pointer return value defined without type");
}
}
else if (func != NULL) {
if (bs_retval->type != NULL) {
func->retval = bs_retval;
}
else {
free(bs_retval);
#if !defined(__LP64__)
if (get_type64_attribute(reader) != NULL) {
// The function has no 32-bit return value type and we
// run in 32-bit mode. We just ignore it.
func = NULL;
break;
}
#endif
BAIL("function '%s' return value defined without type",
func->name);
}
}
else {
method->retval = bs_retval;
}
if (get_boolean_attribute(reader, "function_pointer", false)) {
if (func_ptr != NULL) {
func_ptr = NULL;
nested_func_ptr = true;
break;
}
bs_retval->function_pointer = (bs_element_function_pointer_t *)
calloc(1, sizeof(bs_element_function_pointer_t));
ASSERT_ALLOC(bs_retval->function_pointer);
func_ptr = bs_retval->function_pointer;
func_ptr_arg_depth = xmlTextReaderDepth(reader);
}
else {
bs_retval->function_pointer = NULL;
}
}
else {
BAIL("return value defined outside a function/method");
}
break;
}
case BS_XML_METHOD:
{
if (protocol_name != NULL) {
bs_element_informal_protocol_method_t *bs_informal_method;
char *selector;
char *method_type;
selector = get_attribute(reader, "selector");
CHECK_ATTRIBUTE(selector, "selector");
method_type = get_type_attribute(reader);
CHECK_TYPE_ATTRIBUTE(method_type);
bs_informal_method = (bs_element_informal_protocol_method_t *)
malloc(sizeof(bs_element_informal_protocol_method_t));
ASSERT_ALLOC(bs_informal_method);
bs_informal_method->name = sel_registerName(selector);
free(selector);
bs_informal_method->class_method =
get_boolean_attribute(reader, "class_method", false);
bs_informal_method->type = method_type;
bs_informal_method->protocol_name = strdup(protocol_name);
bs_element = bs_informal_method;
bs_element_type = BS_ELEMENT_INFORMAL_PROTOCOL_METHOD;
}
else if (klass != NULL) {
char *selector;
selector = get_attribute(reader, "selector");
CHECK_ATTRIBUTE(selector, "selector");
method =
(bs_element_method_t *)malloc(sizeof(bs_element_method_t));
ASSERT_ALLOC(method);
method->name = sel_registerName(selector);
free(selector);
method->class_method =
get_boolean_attribute(reader, "class_method", false);
method->variadic =
get_boolean_attribute(reader, "variadic", false);
method->ignore =
get_boolean_attribute(reader, "ignore", false);
method->suggestion = get_attribute(reader, "suggestion");
method->args_count = 0;
method->args = NULL;
method->retval = NULL;
if (xmlTextReaderIsEmptyElement(reader)) {
goto index_method;
}
}
else {
BAIL("method defined outside a class or informal protocol");
}
break;
}
}
}
else if (node_type == XML_READER_TYPE_END_ELEMENT) {
switch (atom->val) {
case BS_XML_INFORMAL_PROTOCOL:
{
protocol_name = NULL;
break;
}
case BS_XML_RETVAL:
case BS_XML_ARG:
{
if (func_ptr != NULL
&& func_ptr_arg_depth == xmlTextReaderDepth(reader)) {
bs_element_retval_t *retval = NULL;
bs_element_arg_t *arg = NULL;
unsigned args_count;
if (atom->val == BS_XML_RETVAL) {
retval = func != NULL ? func->retval : method->retval;
}
else {
args_count = func != NULL ? func->args_count
: method->args_count;
arg = &args[args_count - 1];
}
// Determine if we deal with a block or a function pointer.
const char *old_type = (retval ? retval->type : arg->type);
const char lambda_type = *old_type == '@'
? _MR_C_LAMBDA_BLOCK
: _MR_C_LAMBDA_FUNCPTR;
char tmp_type[1025]; // 3 less to fit <, type and >
char new_type[1028];
// Function ptr return type
strlcpy(tmp_type, func_ptr->retval->type, sizeof(tmp_type));
// Function ptr args
for (i = 0; i < func_ptr->args_count; i++) {
strlcat(tmp_type, fptr_args[i].type, sizeof(tmp_type));
}
// Clear the final type string
memset(new_type, 0, sizeof(new_type));
// Append the function pointer type
snprintf(new_type, sizeof(new_type), "%c%c%s%c",
_MR_C_LAMBDA_B, lambda_type, tmp_type, _MR_C_LAMBDA_E);
// Free the old values
if (retval) {
free(retval->type);
retval->type = strdup(new_type);
}
else {
free(arg->type);
arg->type = strdup(new_type);
}
if (func_ptr->args_count > 0) {
size_t len;
len = sizeof(bs_element_arg_t) * func_ptr->args_count;
func_ptr->args = (bs_element_arg_t *)malloc(len);
ASSERT_ALLOC(func_ptr->args);
memcpy(func_ptr->args, fptr_args, len);
}
else {
func_ptr->args = NULL;
}
func_ptr = NULL;
func_ptr_arg_depth = -1;
}
break;
}
case BS_XML_FUNCTION:
{
if (func == NULL) {
break;
}
for (i = 0; i < func->args_count; i++) {
if (args[i].type == NULL)
BAIL("function '%s' argument #%d type not provided",
func->name, i);
}
if (func->args_count > 0) {
size_t len;
len = sizeof(bs_element_arg_t) * func->args_count;
func->args = (bs_element_arg_t *)malloc(len);
ASSERT_ALLOC(func->args);
memcpy(func->args, args, len);
}
bs_element = func;
bs_element_type = BS_ELEMENT_FUNCTION;
func = NULL;
break;
}
case BS_XML_METHOD:
{
bs_element_method_t *methods;
unsigned *methods_count;
if (method->args_count > 0) {
size_t len;
len = sizeof(bs_element_arg_t) * method->args_count;
method->args = (bs_element_arg_t *)malloc(len);
ASSERT_ALLOC(method->args);
memcpy(method->args, args, len);
}
index_method:
methods = method->class_method
? klass->class_methods : klass->instance_methods;
methods_count = method->class_method
? &klass->class_methods_count : &klass->instance_methods_count;
if (methods == NULL) {
methods = (bs_element_method_t *)malloc(
sizeof(bs_element_method_t) * (*methods_count + 1));
}
else {
methods = (bs_element_method_t *)realloc(methods,
sizeof(bs_element_method_t) * (*methods_count + 1));
}
ASSERT_ALLOC(methods);
// methods[*methods_count] = method;
// FIXME this is inefficient
memcpy(&methods[*methods_count], method,
sizeof(bs_element_method_t));
(*methods_count)++;
if (method->class_method)
klass->class_methods = methods;
else
klass->instance_methods = methods;
free(method);
method = NULL;
break;
}
case BS_XML_CLASS:
{
bs_element = klass;
bs_element_type = BS_ELEMENT_CLASS;
klass = NULL;
break;
}
}
}
if (bs_element != NULL)
(*callback)(parser, path, bs_element_type, bs_element, context);
}
success = true;
bails:
if (protocol_name != NULL)
free(protocol_name);
xmlFreeTextReader(reader);
if (!success) {
for (unsigned i = 0, count = CFArrayGetCount(parser->loaded_paths);
i < count; i++) {
CFStringRef s = CFArrayGetValueAtIndex(parser->loaded_paths, i);
if (CFStringCompare(cf_path, s, kCFCompareCaseInsensitive)
== kCFCompareEqualTo) {
CFArrayRemoveValueAtIndex(parser->loaded_paths, i);
break;
}
}
}
if (success && options == BS_PARSE_OPTIONS_LOAD_DYLIBS && framework_path != NULL) {
char buf[PATH_MAX];
if (_bs_find_path(framework_path, buf, sizeof buf, "dylib")) {
if (dlopen(buf, RTLD_LAZY) == NULL) {
if (error != NULL) {
*error = dlerror();
}
success = false;
}
}
}
return success;
}
unsigned int
bs_parser_current_version_number(bs_parser_t *parser)
{
return parser->version_number;
}
#define SAFE_FREE(x) do { if ((x) != NULL) free(x); } while (0)
static void bs_free_retval(bs_element_retval_t *bs_retval);
static void bs_free_arg(bs_element_arg_t *bs_arg);
static void
bs_free_function_pointer(bs_element_function_pointer_t *bs_func_ptr)
{
if (bs_func_ptr != NULL) {
unsigned i;
for (i = 0; i < bs_func_ptr->args_count; i++)
bs_free_arg(&bs_func_ptr->args[i]);
SAFE_FREE(bs_func_ptr->args);
bs_free_retval(bs_func_ptr->retval);
SAFE_FREE(bs_func_ptr);
}
}
static void
bs_free_retval(bs_element_retval_t *bs_retval)
{
if (bs_retval == NULL)
return;
SAFE_FREE(bs_retval->type);
bs_free_function_pointer(bs_retval->function_pointer);
}
static void
bs_free_arg(bs_element_arg_t *bs_arg)
{
SAFE_FREE(bs_arg->type);
SAFE_FREE(bs_arg->sel_of_type);
bs_free_function_pointer(bs_arg->function_pointer);
}
static void
bs_free_method(bs_element_method_t *bs_method)
{
unsigned i;
for (i = 0; i < bs_method->args_count; i++)
bs_free_arg(&bs_method->args[i]);
SAFE_FREE(bs_method->args);
bs_free_retval(bs_method->retval);
SAFE_FREE(bs_method->suggestion);
}
void
bs_element_free(bs_element_type_t type, void *value)
{
assert(value != NULL);
switch (type) {
case BS_ELEMENT_STRUCT:
{
bs_element_struct_t *bs_struct = (bs_element_struct_t *)value;
unsigned i;
SAFE_FREE(bs_struct->name);
SAFE_FREE(bs_struct->type);
for (i = 0; i < bs_struct->fields_count; i++) {
SAFE_FREE(bs_struct->fields[i].name);
SAFE_FREE(bs_struct->fields[i].type);
}
SAFE_FREE(bs_struct->fields);
break;
}
case BS_ELEMENT_CFTYPE:
{
bs_element_cftype_t *bs_cftype = (bs_element_cftype_t *)value;
SAFE_FREE(bs_cftype->name);
SAFE_FREE(bs_cftype->type);
SAFE_FREE(bs_cftype->tollfree);
break;
}
case BS_ELEMENT_OPAQUE:
{
bs_element_opaque_t *bs_opaque = (bs_element_opaque_t *)value;
SAFE_FREE(bs_opaque->name);
SAFE_FREE(bs_opaque->type);
break;
}
case BS_ELEMENT_CONSTANT:
{
bs_element_constant_t *bs_const = (bs_element_constant_t *)value;
SAFE_FREE(bs_const->name);
SAFE_FREE(bs_const->type);
SAFE_FREE(bs_const->suggestion);
break;
}
case BS_ELEMENT_STRING_CONSTANT:
{
bs_element_string_constant_t *bs_str_const =
(bs_element_string_constant_t *)value;
SAFE_FREE(bs_str_const->name);
SAFE_FREE(bs_str_const->value);
break;
}
case BS_ELEMENT_ENUM:
{
bs_element_enum_t *bs_enum = (bs_element_enum_t *)value;
SAFE_FREE(bs_enum->name);
SAFE_FREE(bs_enum->value);
SAFE_FREE(bs_enum->suggestion);
break;
}
case BS_ELEMENT_FUNCTION:
{
unsigned i;
bs_element_function_t *bs_func = (bs_element_function_t *)value;
free(bs_func->name);
for (i = 0; i < bs_func->args_count; i++)
bs_free_arg(&bs_func->args[i]);
SAFE_FREE(bs_func->args);
bs_free_retval(bs_func->retval);
break;
}
case BS_ELEMENT_FUNCTION_ALIAS:
{
bs_element_function_alias_t *bs_func_alias =
(bs_element_function_alias_t *)value;
SAFE_FREE(bs_func_alias->name);
SAFE_FREE(bs_func_alias->original);
break;
}
case BS_ELEMENT_CLASS:
{
bs_element_class_t *bs_class = (bs_element_class_t *)value;
unsigned i;
free(bs_class->name);
for (i = 0; i < bs_class->class_methods_count; i++)
bs_free_method(&bs_class->class_methods[i]);
SAFE_FREE(bs_class->class_methods);
for (i = 0; i < bs_class->instance_methods_count; i++)
bs_free_method(&bs_class->instance_methods[i]);
SAFE_FREE(bs_class->instance_methods);
break;
}
case BS_ELEMENT_INFORMAL_PROTOCOL_METHOD:
{
bs_element_informal_protocol_method_t *bs_iprotm =
(bs_element_informal_protocol_method_t *)value;
SAFE_FREE(bs_iprotm->protocol_name);
SAFE_FREE(bs_iprotm->type);
break;
}
default:
fprintf(stderr, "unknown value %p of type %d passed to bs_free()",
value, type);
}
free(value);
}
#endif // !MACRUBY_STATIC
Jump to Line
Something went wrong with that request. Please try again.