blob: c47c8c62c13f3ef93cbef85f0d847de2e9bd54a0 [file] [log] [blame]
/**
*Licensed to the Apache Software Foundation (ASF) under one
*or more contributor license agreements. See the NOTICE file
*distributed with this work for additional information
*regarding copyright ownership. The ASF licenses this file
*to you under the Apache License, Version 2.0 (the
*"License"); you may not use this file except in compliance
*with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing,
*software distributed under the License is distributed on an
*"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
*specific language governing permissions and limitations
*under the License.
*/
#include "dyn_type.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include "dyn_common.h"
DFI_SETUP_LOG(dynType)
static int dynType_parseWithStream(FILE *stream, const char *name, dyn_type *parent, struct types_head *refTypes, dyn_type **result);
static void dynType_clear(dyn_type *type);
static void dynType_clearComplex(dyn_type *type);
static void dynType_clearSequence(dyn_type *type);
static void dynType_clearTypedPointer(dyn_type *type);
static struct type_entry *dynType_allocTypeEntry(void);
static ffi_type * dynType_ffiTypeFor(int c);
static dyn_type * dynType_findType(dyn_type *type, char *name);
static int dynType_parseAny(FILE *stream, dyn_type *type);
static int dynType_parseComplex(FILE *stream, dyn_type *type);
static int dynType_parseNestedType(FILE *stream, dyn_type *type);
static int dynType_parseReference(FILE *stream, dyn_type *type);
static int dynType_parseRefByValue(FILE *stream, dyn_type *type);
static int dynType_parseSequence(FILE *stream, dyn_type *type);
static int dynType_parseSimple(int c, dyn_type *type);
static int dynType_parseTypedPointer(FILE *stream, dyn_type *type);
static void dynType_prepCif(ffi_type *type);
static unsigned short dynType_getOffset(dyn_type *type, int index);
static void dynType_printAny(char *name, dyn_type *type, int depth, FILE *stream);
static void dynType_printComplex(char *name, dyn_type *type, int depth, FILE *stream);
static void dynType_printSequence(char *name, dyn_type *type, int depth, FILE *stream);
static void dynType_printSimple(char *name, dyn_type *type, int depth, FILE *stream);
static void dynType_printTypedPointer(char *name, dyn_type *type, int depth, FILE *stream);
static void dynType_printDepth(int depth, FILE *stream);
static void dynType_printTypes(dyn_type *type, FILE *stream);
static void dynType_printComplexType(dyn_type *type, FILE *stream);
static void dynType_printSimpleType(dyn_type *type, FILE *stream);
static int dynType_parseText(FILE *stream, dyn_type *type);
void dynType_freeComplexType(dyn_type *type, void *loc);
void dynType_deepFree(dyn_type *type, void *loc, bool alsoDeleteSelf);
void dynType_freeSequenceType(dyn_type *type, void *seqLoc);
static int dynType_parseMetaInfo(FILE *stream, dyn_type *type);
struct generic_sequence {
uint32_t cap;
uint32_t len;
void *buf;
};
TAILQ_HEAD(meta_properties_head, meta_entry);
struct meta_entry {
char *name;
char *value;
TAILQ_ENTRY(meta_entry) entries;
};
struct _dyn_type {
char *name;
char descriptor;
int type;
ffi_type *ffiType;
dyn_type *parent;
struct types_head *referenceTypes; //NOTE: not owned
struct types_head nestedTypesHead;
struct meta_properties_head metaProperties;
union {
struct {
struct complex_type_entries_head entriesHead;
ffi_type structType; //dyn_type.ffiType points to this
dyn_type **types; //based on entriesHead for fast access
} complex;
struct {
ffi_type seqType; //dyn_type.ffiType points to this
dyn_type *itemType;
} sequence;
struct {
dyn_type *typedType;
} typedPointer;
struct {
dyn_type *ref;
} ref;
};
};
static const int OK = 0;
static const int ERROR = 1;
static const int MEM_ERROR = 2;
static const int PARSE_ERROR = 3;
int dynType_parse(FILE *descriptorStream, const char *name, struct types_head *refTypes, dyn_type **type) {
return dynType_parseWithStream(descriptorStream, name, NULL, refTypes, type);
}
int dynType_parseWithStr(const char *descriptor, const char *name, struct types_head *refTypes, dyn_type **type) {
int status = OK;
FILE *stream = fmemopen((char *)descriptor, strlen(descriptor), "r");
if (stream != NULL) {
status = dynType_parseWithStream(stream, name, NULL, refTypes, type);
if (status == OK) {
int c = fgetc(stream);
if (c != '\0' && c != EOF) {
status = PARSE_ERROR;
LOG_ERROR("Expected EOF got %c", c);
}
}
fclose(stream);
} else {
status = ERROR;
LOG_ERROR("Error creating mem stream for descriptor string. %s", strerror(errno));
}
return status;
}
static int dynType_parseWithStream(FILE *stream, const char *name, dyn_type *parent, struct types_head *refTypes, dyn_type **result) {
int status = OK;
dyn_type *type = calloc(1, sizeof(*type));
if (type != NULL) {
type->parent = parent;
type->type = DYN_TYPE_INVALID;
type->referenceTypes = refTypes;
TAILQ_INIT(&type->nestedTypesHead);
TAILQ_INIT(&type->metaProperties);
if (name != NULL) {
type->name = strdup(name);
if (type->name == NULL) {
status = MEM_ERROR;
LOG_ERROR("Error strdup'ing name '%s'\n", name);
}
}
if (status == OK) {
status = dynType_parseAny(stream, type);
}
if (status == OK) {
*result = type;
} else {
dynType_destroy(type);
}
} else {
status = MEM_ERROR;
LOG_ERROR("Error allocating memory for type");
}
return status;
}
static int dynType_parseAny(FILE *stream, dyn_type *type) {
int status = OK;
int c = fgetc(stream);
switch(c) {
case 'T' :
status = dynType_parseNestedType(stream, type);
if (status == OK) {
status = dynType_parseAny(stream, type);
}
break;
case 'L' :
status = dynType_parseReference(stream, type);
break;
case 'l' :
status = dynType_parseRefByValue(stream, type);
break;
case '{' :
status = dynType_parseComplex(stream, type);
break;
case '[' :
status = dynType_parseSequence(stream, type);
break;
case '*' :
status = dynType_parseTypedPointer(stream, type);
break;
case 't' :
status = dynType_parseText(stream, type);
break;
case '#' :
status = dynType_parseMetaInfo(stream, type);
if (status == OK) {
status = dynType_parseAny(stream, type);
}
break;
default :
status = dynType_parseSimple(c, type);
break;
}
return status;
}
static int dynType_parseMetaInfo(FILE *stream, dyn_type *type) {
int status = OK;
char *name = NULL;
char *value = NULL;
struct meta_entry *entry = calloc(1, sizeof(*entry));
if (entry == NULL) {
status = ERROR;
}
if (status == OK) {
status = dynCommon_parseName(stream, &name);
}
if (status == OK) {
status = dynCommon_eatChar(stream, '=');
}
if (status == OK) {
status = dynCommon_parseName(stream, &value);
}
if (status == OK) {
status = dynCommon_eatChar(stream, ';');
}
if (status == OK) {
entry->name = name;
entry->value = value;
TAILQ_INSERT_TAIL(&type->metaProperties, entry, entries);
LOG_DEBUG("Added meta properties '%s':'%s'", name, value)
} else {
free(name);
free(value);
free(entry);
}
return status;
}
static int dynType_parseText(FILE *stream, dyn_type *type) {
int status = OK;
type->type = DYN_TYPE_TEXT;
type->descriptor = 't';
type->ffiType = &ffi_type_pointer;
return status;
}
static int dynType_parseComplex(FILE *stream, dyn_type *type) {
int status = OK;
type->type = DYN_TYPE_COMPLEX;
type->descriptor = '{';
type->ffiType = &type->complex.structType;
TAILQ_INIT(&type->complex.entriesHead);
int c = fgetc(stream);
struct complex_type_entry *entry = NULL;
while (c != ' ' && c != '}') {
ungetc(c,stream);
entry = calloc(1, sizeof(*entry));
if (entry != NULL) {
entry->type = calloc(1, sizeof(*entry->type));
}
if (entry != NULL && entry->type != NULL) {
entry->type->parent = type;
entry->type->type = DYN_TYPE_INVALID;
TAILQ_INIT(&entry->type->nestedTypesHead);
TAILQ_INIT(&entry->type->metaProperties);
TAILQ_INSERT_TAIL(&type->complex.entriesHead, entry, entries);
status = dynType_parseAny(stream, entry->type);
} else {
if (entry != NULL) {
free(entry);
}
status = MEM_ERROR;
LOG_ERROR("Error allocating memory for type");
}
c = fgetc(stream);
}
entry = TAILQ_FIRST(&type->complex.entriesHead);
char *name = NULL;
while (c == ' ' && entry != NULL) {
status = dynCommon_parseName(stream, &name);
if (status == OK) {
entry->name = name;
entry = TAILQ_NEXT(entry, entries);
} else {
break;
}
c = getc(stream);
}
int count = 0;
TAILQ_FOREACH(entry, &type->complex.entriesHead, entries) {
count +=1;
}
if (status == OK) {
type->complex.structType.type = FFI_TYPE_STRUCT;
type->complex.structType.elements = calloc(count + 1, sizeof(ffi_type));
if (type->complex.structType.elements != NULL) {
type->complex.structType.elements[count] = NULL;
int index = 0;
TAILQ_FOREACH(entry, &type->complex.entriesHead, entries) {
type->complex.structType.elements[index++] = dynType_ffiType(entry->type);
}
} else {
status = MEM_ERROR;
//T\nODO log: error allocating memory
}
}
if (status == OK) {
type->complex.types = calloc(count, sizeof(dyn_type *));
if (type != NULL) {
int index = 0;
TAILQ_FOREACH(entry, &type->complex.entriesHead, entries) {
type->complex.types[index++] = entry->type;
}
} else {
status = MEM_ERROR;
LOG_ERROR("Error allocating memory for type")
}
}
if (status == OK) {
dynType_prepCif(type->ffiType);
}
return status;
}
static int dynType_parseNestedType(FILE *stream, dyn_type *type) {
int status = OK;
char *name = NULL;
struct type_entry *entry = NULL;
entry = dynType_allocTypeEntry();
if (entry != NULL) {
entry->type->parent = type;
entry->type->type = DYN_TYPE_INVALID;
TAILQ_INIT(&entry->type->nestedTypesHead);
TAILQ_INIT(&entry->type->metaProperties);
TAILQ_INSERT_TAIL(&type->nestedTypesHead, entry, entries);
status = dynCommon_parseName(stream, &name);
entry->type->name = name;
} else {
status = MEM_ERROR;
LOG_ERROR("Error allocating entry");
}
if (status == OK) {
int c = fgetc(stream);
if (c != '=') {
status = PARSE_ERROR;
LOG_ERROR("Error parsing nested type expected '=' got '%c'", c);
}
}
if (status == OK) {
status = dynType_parseAny(stream, entry->type);
int c = fgetc(stream);
if (c != ';') {
status = PARSE_ERROR;
LOG_ERROR("Expected ';' got '%c'\n", c);
}
}
return status;
}
static int dynType_parseReference(FILE *stream, dyn_type *type) {
int status = OK;
type->type = DYN_TYPE_TYPED_POINTER;
type->descriptor = '*';
type->ffiType = &ffi_type_pointer;
type->typedPointer.typedType = NULL;
dyn_type *subType = calloc(1, sizeof(*subType));
if (subType != NULL) {
type->typedPointer.typedType = subType;
subType->parent = type;
subType->type = DYN_TYPE_INVALID;
TAILQ_INIT(&subType->nestedTypesHead);
TAILQ_INIT(&subType->metaProperties);
status = dynType_parseRefByValue(stream, subType);
} else {
status = MEM_ERROR;
LOG_ERROR("Error allocating memory for subtype\n");
}
return status;
}
static int dynType_parseRefByValue(FILE *stream, dyn_type *type) {
int status = OK;
type->type = DYN_TYPE_REF;
type->descriptor = 'l';
char *name = NULL;
status = dynCommon_parseName(stream, &name);
if (status == OK) {
dyn_type *ref = dynType_findType(type, name);
if (ref != NULL) {
type->ref.ref = ref;
} else {
status = PARSE_ERROR;
LOG_ERROR("Error cannot find type '%s'", name);
}
free(name);
}
if (status == OK) {
int c = fgetc(stream);
if (c != ';') {
status = PARSE_ERROR;
LOG_ERROR("Error expected ';' got '%c'", c);
}
}
return status;
}
static struct type_entry *dynType_allocTypeEntry(void) {
struct type_entry *entry = calloc(1, sizeof(*entry));
if (entry != NULL) {
entry->type = calloc(1, sizeof(*entry->type));
if (entry->type == NULL) {
free(entry);
entry = NULL;
}
}
return entry;
}
static ffi_type *seq_types[] = {&ffi_type_uint32, &ffi_type_uint32, &ffi_type_pointer, NULL};
static int dynType_parseSequence(FILE *stream, dyn_type *type) {
int status = OK;
type->type = DYN_TYPE_SEQUENCE;
type->descriptor = '[';
type->sequence.seqType.elements = seq_types;
type->sequence.seqType.type = FFI_TYPE_STRUCT;
type->sequence.seqType.size = 0;
type->sequence.seqType.alignment = 0;
status = dynType_parseWithStream(stream, NULL, type, NULL, &type->sequence.itemType);
if (status == OK) {
type->ffiType = &type->sequence.seqType;
dynType_prepCif(&type->sequence.seqType);
}
return status;
}
static int dynType_parseSimple(int c, dyn_type *type) {
int status = OK;
ffi_type *ffiType = dynType_ffiTypeFor(c);
if (ffiType != NULL) {
type->type = DYN_TYPE_SIMPLE;
type->descriptor = c;
type->ffiType = ffiType;
} else {
status = PARSE_ERROR;
LOG_ERROR("Error unsupported type '%c'", c);
}
return status;
}
static int dynType_parseTypedPointer(FILE *stream, dyn_type *type) {
int status = OK;
type->type = DYN_TYPE_TYPED_POINTER;
type->descriptor = '*';
type->ffiType = &ffi_type_pointer;
status = dynType_parseWithStream(stream, NULL, type, NULL, &type->typedPointer.typedType);
return status;
}
static void dynType_prepCif(ffi_type *type) {
ffi_cif cif;
ffi_type *args[1];
args[0] = type;
ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_uint, args);
}
void dynType_destroy(dyn_type *type) {
if (type != NULL) {
dynType_clear(type);
free(type);
}
}
static void dynType_clear(dyn_type *type) {
struct type_entry *entry = TAILQ_FIRST(&type->nestedTypesHead);
struct type_entry *tmp = NULL;
while (entry != NULL) {
tmp = entry;
entry = TAILQ_NEXT(entry, entries);
if (tmp->type != NULL) {
dynType_destroy(tmp->type);
tmp->type = NULL;
}
free(tmp);
}
struct meta_entry *mEntry = TAILQ_FIRST(&type->metaProperties);;
struct meta_entry *next = NULL;
while (mEntry != NULL) {
next = TAILQ_NEXT(mEntry, entries);
if (mEntry != NULL) {
free(mEntry->name);
free(mEntry->value);
free(mEntry);
}
mEntry = next;
}
switch (type->type) {
case DYN_TYPE_COMPLEX :
dynType_clearComplex(type);
break;
case DYN_TYPE_SEQUENCE :
dynType_clearSequence(type);
break;
case DYN_TYPE_TYPED_POINTER :
dynType_clearTypedPointer(type);
break;
}
if (type->name != NULL) {
free(type->name);
}
}
static void dynType_clearComplex(dyn_type *type) {
assert(type->type == DYN_TYPE_COMPLEX);
struct complex_type_entry *entry = TAILQ_FIRST(&type->complex.entriesHead);
struct complex_type_entry *tmp = NULL;
while (entry != NULL) {
dynType_destroy(entry->type);
if (entry->name != NULL) {
free(entry->name);
}
tmp = entry;
entry = TAILQ_NEXT(entry, entries);
free(tmp);
}
if (type->complex.types != NULL) {
free(type->complex.types);
}
if (type->complex.structType.elements != NULL) {
free(type->complex.structType.elements);
}
}
static void dynType_clearSequence(dyn_type *type) {
assert(type->type == DYN_TYPE_SEQUENCE);
if (type->sequence.itemType != NULL) {
dynType_destroy(type->sequence.itemType);
}
}
static void dynType_clearTypedPointer(dyn_type *type) {
assert(type->type == DYN_TYPE_TYPED_POINTER);
if (type->typedPointer.typedType != NULL) {
dynType_destroy(type->typedPointer.typedType);
}
}
int dynType_alloc(dyn_type *type, void **bufLoc) {
assert(type->type != DYN_TYPE_REF);
assert(type->ffiType->size != 0);
int status = OK;
void *inst = calloc(1, type->ffiType->size);
if (inst != NULL) {
if (type->type == DYN_TYPE_TYPED_POINTER) {
void *ptr = NULL;
dyn_type *sub = NULL;
status = dynType_typedPointer_getTypedType(type, &sub);
if (status == OK) {
status = dynType_alloc(sub, &ptr);
if (status == OK) {
*(void **)inst = ptr;
}
}
}
*bufLoc = inst;
} else {
status = MEM_ERROR;
LOG_ERROR("Error allocating memory for type '%c'", type->descriptor);
}
return status;
}
int dynType_complex_indexForName(dyn_type *type, const char *name) {
assert(type->type == DYN_TYPE_COMPLEX);
int i = 0;
int index = -1;
struct complex_type_entry *entry = NULL;
TAILQ_FOREACH(entry, &type->complex.entriesHead, entries) {
if (strcmp(name, entry->name) == 0) {
index = i;
}
i +=1;
}
return index;
}
int dynType_complex_dynTypeAt(dyn_type *type, int index, dyn_type **result) {
assert(type->type == DYN_TYPE_COMPLEX);
dyn_type *sub = type->complex.types[index];
if (sub->type == DYN_TYPE_REF) {
sub = sub->ref.ref;
}
*result = sub;
return 0;
}
int dynType_complex_setValueAt(dyn_type *type, int index, void *start, void *in) {
assert(type->type == DYN_TYPE_COMPLEX);
char *loc = ((char *)start) + dynType_getOffset(type, index);
size_t size = type->complex.structType.elements[index]->size;
memcpy(loc, in, size);
return 0;
}
int dynType_complex_valLocAt(dyn_type *type, int index, void *inst, void **result) {
assert(type->type == DYN_TYPE_COMPLEX);
char *l = (char *)inst;
void *loc = (void *)(l + dynType_getOffset(type, index));
*result = loc;
return 0;
}
int dynType_complex_entries(dyn_type *type, struct complex_type_entries_head **entries) {
assert(type->type == DYN_TYPE_COMPLEX);
int status = OK;
*entries = &type->complex.entriesHead;
return status;
}
//sequence
int dynType_sequence_alloc(dyn_type *type, void *inst, uint32_t cap) {
assert(type->type == DYN_TYPE_SEQUENCE);
int status = OK;
struct generic_sequence *seq = inst;
if (seq != NULL) {
size_t size = dynType_size(type->sequence.itemType);
seq->buf = calloc(cap, size);
if (seq->buf != NULL) {
seq->cap = cap;
seq->len = 0;;
} else {
seq->cap = 0;
status = MEM_ERROR;
LOG_ERROR("Error allocating memory for buf")
}
} else {
status = MEM_ERROR;
LOG_ERROR("Error allocating memory for seq")
}
return status;
}
void dynType_free(dyn_type *type, void *loc) {
dynType_deepFree(type, loc, true);
}
void dynType_deepFree(dyn_type *type, void *loc, bool alsoDeleteSelf) {
if (loc != NULL) {
dyn_type *subType = NULL;
char *text = NULL;
switch (type->type) {
case DYN_TYPE_COMPLEX :
dynType_freeComplexType(type, loc);
break;
case DYN_TYPE_SEQUENCE :
dynType_freeSequenceType(type, loc);
break;
case DYN_TYPE_TYPED_POINTER:
dynType_typedPointer_getTypedType(type, &subType);
dynType_deepFree(subType, *(void **)loc, true);
break;
case DYN_TYPE_TEXT :
text = *(char **)loc;
free(text);
break;
}
if (alsoDeleteSelf) {
free(loc);
}
}
}
void dynType_freeSequenceType(dyn_type *type, void *seqLoc) {
struct generic_sequence *seq = seqLoc;
dyn_type *itemType = dynType_sequence_itemType(type);
void *itemLoc = NULL;
int i;
for (i = 0; i < seq->len; i += 1) {
dynType_sequence_locForIndex(type, seqLoc, i, &itemLoc);
dynType_deepFree(itemType, itemLoc, false);
}
free(seq->buf);
}
void dynType_freeComplexType(dyn_type *type, void *loc) {
struct complex_type_entry *entry = NULL;
int index = 0;
void *entryLoc = NULL;
TAILQ_FOREACH(entry, &type->complex.entriesHead, entries) {
dynType_complex_valLocAt(type, index++, loc, &entryLoc);
dynType_deepFree(entry->type, entryLoc, false);
}
}
uint32_t dynType_sequence_length(void *seqLoc) {
struct generic_sequence *seq = seqLoc;
return seq->len;
}
int dynType_sequence_locForIndex(dyn_type *type, void *seqLoc, int index, void **out) {
assert(type->type == DYN_TYPE_SEQUENCE);
int status = OK;
struct generic_sequence *seq = seqLoc;
char *valLoc = seq->buf;
size_t itemSize = dynType_size(type->sequence.itemType);
if (index >= seq->cap) {
status = ERROR;
LOG_ERROR("Requested index (%i) is greater than capacity (%u) of sequence", index, seq->cap);
}
if (index >= seq->len) {
LOG_WARNING("Requesting index (%i) outsize defined length (%u) but within capacity", index, seq->len);
}
if (status == OK) { }
int i;
for (i = 0; i < seq->cap; i += 1) {
if (index == i) {
break;
} else {
valLoc += itemSize;
}
}
(*out) = valLoc;
return status;
}
int dynType_sequence_increaseLengthAndReturnLastLoc(dyn_type *type, void *seqLoc, void **valLoc) {
assert(type->type == DYN_TYPE_SEQUENCE);
int status = OK;
struct generic_sequence *seq = seqLoc;
int lastIndex = seq->len;
if (seq->len < seq->cap) {
seq->len += 1;
} else {
status = ERROR;
LOG_ERROR("Cannot increase sequence length beyond capacity (%u)", seq->cap);
}
if (status == OK) {
status = dynType_sequence_locForIndex(type, seqLoc, lastIndex, valLoc);
}
return status;
}
dyn_type * dynType_sequence_itemType(dyn_type *type) {
assert(type->type == DYN_TYPE_SEQUENCE);
dyn_type *itemType = type->sequence.itemType;
if (itemType->type == DYN_TYPE_REF) {
itemType = itemType->ref.ref;
}
return itemType;
}
void dynType_simple_setValue(dyn_type *type, void *inst, void *in) {
size_t size = dynType_size(type);
memcpy(inst, in, size);
}
int dynType_descriptorType(dyn_type *type) {
return type->descriptor;
}
const char * dynType_getMetaInfo(dyn_type *type, const char *name) {
const char *result = NULL;
struct meta_entry *entry = NULL;
TAILQ_FOREACH(entry, &type->metaProperties, entries) {
LOG_DEBUG("Checking '%s'", entry->name);
if (strcmp(entry->name, name) == 0) {
result = entry->value;
break;
}
}
return result;
}
ffi_type *dynType_ffiType(dyn_type *type) {
if (type->type == DYN_TYPE_REF) {
return type->ref.ref->ffiType;
}
return type->ffiType;
}
static ffi_type * dynType_ffiTypeFor(int c) {
ffi_type *type = NULL;
switch (c) {
case 'Z' :
type = &ffi_type_uint8;
break;
case 'F' :
type = &ffi_type_float;
break;
case 'D' :
type = &ffi_type_double;
break;
case 'B' :
type = &ffi_type_sint8;
break;
case 'b' :
type = &ffi_type_uint8;
break;
case 'S' :
type = &ffi_type_sint16;
break;
case 's' :
type = &ffi_type_uint16;
break;
case 'I' :
type = &ffi_type_sint32;
break;
case 'i' :
type = &ffi_type_uint32;
break;
case 'J' :
type = &ffi_type_sint64;
break;
case 'j' :
type = &ffi_type_sint64;
break;
case 'N' :
type = &ffi_type_sint;
break;
case 'P' :
type = &ffi_type_pointer;
break;
case 'V' :
type = &ffi_type_void;
break;
}
return type;
}
static dyn_type * dynType_findType(dyn_type *type, char *name) {
dyn_type *result = NULL;
struct type_entry *entry = NULL;
if (type->referenceTypes != NULL) {
TAILQ_FOREACH(entry, type->referenceTypes, entries) {
LOG_DEBUG("checking ref type '%s' with name '%s'", entry->type->name, name);
if (strcmp(name, entry->type->name) == 0) {
result = entry->type;
break;
}
}
}
if (result == NULL) {
struct type_entry *nEntry = NULL;
TAILQ_FOREACH(nEntry, &type->nestedTypesHead, entries) {
LOG_DEBUG("checking nested type '%s' with name '%s'", nEntry->type->name, name);
if (strcmp(name, nEntry->type->name) == 0) {
result = nEntry->type;
break;
}
}
}
if (result == NULL && type->parent != NULL) {
result = dynType_findType(type->parent, name);
}
return result;
}
static unsigned short dynType_getOffset(dyn_type *type, int index) {
assert(type->type == DYN_TYPE_COMPLEX);
unsigned short offset = 0;
ffi_type *ffiType = &type->complex.structType;
int i;
for (i = 0; i <= index && ffiType->elements[i] != NULL; i += 1) {
size_t size = ffiType->elements[i]->size;
unsigned short alignment = ffiType->elements[i]->alignment;
int alignment_diff = offset % alignment;
if (alignment_diff > 0) {
offset += (alignment - alignment_diff);
}
if (i < index) {
offset += size;
}
}
return offset;
}
size_t dynType_size(dyn_type *type) {
dyn_type *rType = type;
if (type->type == DYN_TYPE_REF) {
rType = type->ref.ref;
}
return rType->ffiType->size;
}
int dynType_type(dyn_type *type) {
return type->type;
}
int dynType_typedPointer_getTypedType(dyn_type *type, dyn_type **out) {
assert(type->type == DYN_TYPE_TYPED_POINTER);
int status = 0;
dyn_type *typedType = type->typedPointer.typedType;
if (typedType->type == DYN_TYPE_REF) {
typedType = typedType->ref.ref;
}
*out = typedType;
return status;
}
int dynType_text_allocAndInit(dyn_type *type, void *textLoc, const char *value) {
assert(type->type == DYN_TYPE_TEXT);
int status = 0;
const char *str = strdup(value);
char const **loc = textLoc;
if (str != NULL) {
*loc = str;
} else {
status = ERROR;
LOG_ERROR("Cannot allocate memory for string");
}
return status;
}
void dynType_print(dyn_type *type, FILE *stream) {
if (type != NULL) {
dynType_printTypes(type, stream);
fprintf(stream, "main type:\n");
dynType_printAny("root", type, 0, stream);
} else {
fprintf(stream, "invalid type\n");
}
}
static void dynType_printDepth(int depth, FILE *stream) {
int i;
for (i = 0; i < depth; i +=1 ) {
fprintf(stream, "\t");
}
}
static void dynType_printAny(char *name, dyn_type *type, int depth, FILE *stream) {
dyn_type *toPrint = type;
if (toPrint->type == DYN_TYPE_REF) {
toPrint = toPrint->ref.ref;
}
switch(toPrint->type) {
case DYN_TYPE_COMPLEX :
dynType_printComplex(name, toPrint, depth, stream);
break;
case DYN_TYPE_SIMPLE :
dynType_printSimple(name, toPrint, depth, stream);
break;
case DYN_TYPE_SEQUENCE :
dynType_printSequence(name, toPrint, depth, stream);
break;
case DYN_TYPE_TYPED_POINTER :
dynType_printTypedPointer(name, toPrint, depth, stream);
break;
default :
fprintf(stream, "TODO Unsupported type %i\n", toPrint->type);
break;
}
}
static void dynType_printComplex(char *name, dyn_type *type, int depth, FILE *stream) {
if (type->name == NULL) {
dynType_printDepth(depth, stream);
fprintf(stream, "%s: complex type (anon), size is %zu, alignment is %i, descriptor is '%c'. fields:\n", name, type->ffiType->size, type->ffiType->alignment, type->descriptor);
struct complex_type_entry *entry = NULL;
TAILQ_FOREACH(entry, &type->complex.entriesHead, entries) {
dynType_printAny(entry->name, entry->type, depth + 1, stream);
}
dynType_printDepth(depth, stream);
fprintf(stream, "}\n");
} else {
dynType_printDepth(depth, stream);
fprintf(stream, "%s: complex type ('%s'), size is %zu, alignment is %i, descriptor is '%c'.\n", name, type->name, type->ffiType->size, type->ffiType->alignment, type->descriptor);
}
}
static void dynType_printSequence(char *name, dyn_type *type, int depth, FILE *stream) {
dynType_printDepth(depth, stream);
fprintf(stream, "sequence, size is %zu, alignment is %i, descriptor is '%c'. fields:\n", type->ffiType->size, type->ffiType->alignment, type->descriptor);
dynType_printDepth(depth + 1, stream);
fprintf(stream, "cap: simple type, size is %zu, alignment is %i.\n", type->sequence.seqType.elements[0]->size, type->sequence.seqType.elements[0]->alignment);
dynType_printDepth(depth + 1, stream);
fprintf(stream, "len: simple type, size is %zu, alignment is %i.\n", type->sequence.seqType.elements[1]->size, type->sequence.seqType.elements[1]->alignment);
dynType_printDepth(depth + 1, stream);
fprintf(stream, "buf: array, size is %zu, alignment is %i. points to ->\n", type->sequence.seqType.elements[2]->size, type->sequence.seqType.elements[2]->alignment);
dynType_printAny("element", type->sequence.itemType, depth + 1, stream);
}
static void dynType_printSimple(char *name, dyn_type *type, int depth, FILE *stream) {
dynType_printDepth(depth, stream);
fprintf(stream, "%s: simple type, size is %zu, alignment is %i, descriptor is '%c'.\n", name, type->ffiType->size, type->ffiType->alignment, type->descriptor);
}
static void dynType_printTypedPointer(char *name, dyn_type *type, int depth, FILE *stream) {
dynType_printDepth(depth, stream);
fprintf(stream, "%s: typed pointer, size is %zu, alignment is %i, points to ->\n", name, type->ffiType->size, type->ffiType->alignment);
char *subName = NULL;
if (name != NULL) {
char buf[128];
snprintf(buf, 128, "*%s", name);
subName = buf;
}
dynType_printAny(subName, type->typedPointer.typedType, depth + 1, stream);
}
static void dynType_printTypes(dyn_type *type, FILE *stream) {
dyn_type *parent = type->parent;
struct type_entry *pentry = NULL;
while (parent != NULL) {
TAILQ_FOREACH(pentry, &parent->nestedTypesHead, entries) {
if (pentry->type == type) {
return;
}
}
parent = parent->parent;
}
struct type_entry *entry = NULL;
TAILQ_FOREACH(entry, &type->nestedTypesHead, entries) {
dyn_type *toPrint = entry->type;
if (toPrint->type == DYN_TYPE_REF) {
toPrint = toPrint->ref.ref;
}
switch(toPrint->type) {
case DYN_TYPE_COMPLEX :
dynType_printComplexType(toPrint, stream);
break;
case DYN_TYPE_SIMPLE :
dynType_printSimpleType(toPrint, stream);
break;
default :
printf("TODO Print Type\n");
break;
}
}
struct complex_type_entry *centry = NULL;
switch(type->type) {
case DYN_TYPE_COMPLEX :
TAILQ_FOREACH(centry, &type->complex.entriesHead, entries) {
dynType_printTypes(centry->type, stream);
}
break;
case DYN_TYPE_SEQUENCE :
dynType_printTypes(type->sequence.itemType, stream);
break;
case DYN_TYPE_TYPED_POINTER :
dynType_printTypes(type->typedPointer.typedType, stream);
break;
}
}
static void dynType_printComplexType(dyn_type *type, FILE *stream) {
fprintf(stream, "type '%s': complex type, size is %zu, alignment is %i, descriptor is '%c'. fields:\n", type->name, type->ffiType->size, type->ffiType->alignment, type->descriptor);
struct complex_type_entry *entry = NULL;
TAILQ_FOREACH(entry, &type->complex.entriesHead, entries) {
dynType_printAny(entry->name, entry->type, 2, stream);
}
fprintf(stream, "}\n");
}
static void dynType_printSimpleType(dyn_type *type, FILE *stream) {
fprintf(stream, "\ttype '%s': simple type, size is %zu, alignment is %i, descriptor is '%c'\n", type->name, type->ffiType->size, type->ffiType->alignment, type->descriptor);
}