http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/dfi/public/include/json_rpc.h ---------------------------------------------------------------------- diff --git a/dfi/public/include/json_rpc.h b/dfi/public/include/json_rpc.h deleted file mode 100644 index 1cc1464..0000000 --- a/dfi/public/include/json_rpc.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - *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. - */ -#ifndef __JSON_RPC_H_ -#define __JSON_RPC_H_ - -#include <jansson.h> -#include "dfi_log_util.h" -#include "dyn_type.h" -#include "dyn_function.h" -#include "dyn_interface.h" - -//logging -DFI_SETUP_LOG_HEADER(jsonRpc); - -int jsonRpc_call(dyn_interface_type *intf, void *service, const char *request, char **out); - - -int jsonRpc_prepareInvokeRequest(dyn_function_type *func, const char *id, void *args[], char **out); -int jsonRpc_handleReply(dyn_function_type *func, const char *reply, void *args[]); - -#endif
http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/dfi/public/include/json_serializer.h ---------------------------------------------------------------------- diff --git a/dfi/public/include/json_serializer.h b/dfi/public/include/json_serializer.h deleted file mode 100644 index 2f91f2b..0000000 --- a/dfi/public/include/json_serializer.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - *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. - */ -#ifndef __JSON_SERIALIZER_H_ -#define __JSON_SERIALIZER_H_ - -#include <jansson.h> -#include "dfi_log_util.h" -#include "dyn_type.h" -#include "dyn_function.h" -#include "dyn_interface.h" - -//logging -DFI_SETUP_LOG_HEADER(jsonSerializer); - -int jsonSerializer_deserialize(dyn_type *type, const char *input, void **result); -int jsonSerializer_deserializeJson(dyn_type *type, json_t *input, void **result); - -int jsonSerializer_serialize(dyn_type *type, const void* input, char **output); -int jsonSerializer_serializeJson(dyn_type *type, const void* input, json_t **out); - -#endif http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/dfi/src/dyn_common.c ---------------------------------------------------------------------- diff --git a/dfi/src/dyn_common.c b/dfi/src/dyn_common.c new file mode 100644 index 0000000..ea8f425 --- /dev/null +++ b/dfi/src/dyn_common.c @@ -0,0 +1,151 @@ +/** + *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_common.h" + +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <stdbool.h> + +#if defined(BSD) || defined(__APPLE__) || defined(ANDROID) +#include "open_memstream.h" +#include "fmemopen.h" +#endif + +static const int OK = 0; +static const int ERROR = 1; + +DFI_SETUP_LOG(dynCommon) + +static bool dynCommon_charIn(int c, const char *acceptedChars); + +int dynCommon_parseName(FILE *stream, char **result) { + return dynCommon_parseNameAlsoAccept(stream, NULL, result); +} + +int dynCommon_parseNameAlsoAccept(FILE *stream, const char *acceptedChars, char **result) { + int status = OK; + + char *buf = NULL; + size_t size = 0; + int strLen = 0; + FILE *name = open_memstream(&buf, &size); + + if (name != NULL) { + int c = getc(stream); + while (isalnum(c) || c == '_' || dynCommon_charIn(c, acceptedChars)) { + fputc(c, name); + c = getc(stream); + strLen += 1; + } + fflush(name); + fclose(name); + ungetc(c, stream); + } else { + status = ERROR; + LOG_ERROR("Error creating mem stream for name. %s", strerror(errno)); + } + + if (status == OK) { + if (strLen == 0) { + status = ERROR; + LOG_ERROR("Parsed empty name"); + } + } + + if (status == OK) { + LOG_DEBUG("Parsed name '%s'", buf); + *result = buf; + } else if (buf != NULL) { + free(buf); + } + + return status; +} + +int dynCommon_parseNameValue(FILE *stream, char **outName, char **outValue) { + int status; + char *name = NULL; + char *value = NULL; + + status = dynCommon_parseName(stream, &name); + if (status == OK) { + status = dynCommon_eatChar(stream, '='); + } + if (status == OK) { + const char *valueAcceptedChars = ".<>{}[]?;:~!@#$%^&*()_+-=,./\\'\""; + + status = dynCommon_parseNameAlsoAccept(stream, valueAcceptedChars, &value); //NOTE use different more lenient function e.g. only stop at '\n' ? + } + + if (status == OK) { + *outName = name; + *outValue = value; + } else { + if (name != NULL) { + free(name); + } + if (value != NULL) { + free(value); + } + } + return status; +} + +int dynCommon_eatChar(FILE *stream, int expected) { + int status = OK; + long loc = ftell(stream); + int c = fgetc(stream); + if (c != expected) { + status = ERROR; + LOG_ERROR("Error parsing, expected token '%c' got '%c' at position %li", expected, c, loc); + } + return status; +} + +static bool dynCommon_charIn(int c, const char *acceptedChars) { + bool status = false; + if (acceptedChars != NULL) { + int i; + for (i = 0; acceptedChars[i] != '\0'; i += 1) { + if (c == acceptedChars[i]) { + status = true; + break; + } + } + } + + return status; +} + +void dynCommon_clearNamValHead(struct namvals_head *head) { + struct namval_entry *entry = TAILQ_FIRST(head); + while (entry != NULL) { + struct namval_entry *tmp = entry; + + if (entry->name != NULL) { + free(entry->name); + } + if (entry->value != NULL) { + free(entry->value); + } + entry = TAILQ_NEXT(entry, entries); + free(tmp); + } +} http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/dfi/src/dyn_function.c ---------------------------------------------------------------------- diff --git a/dfi/src/dyn_function.c b/dfi/src/dyn_function.c new file mode 100644 index 0000000..615ad16 --- /dev/null +++ b/dfi/src/dyn_function.c @@ -0,0 +1,331 @@ +/** + *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_function.h" + +#include <strings.h> +#include <stdlib.h> +#include <ffi.h> + +#include "dyn_common.h" + +struct _dyn_function_type { + char *name; + struct types_head *refTypes; //NOTE not owned + TAILQ_HEAD(,_dyn_function_argument_type) arguments; + ffi_type **ffiArguments; + dyn_type *funcReturn; + ffi_cif cif; + + //closure part + ffi_closure *ffiClosure; + void (*fn)(void); + void *userData; + void (*bind)(void *userData, void *args[], void *ret); +}; + +typedef struct _dyn_function_argument_type dyn_function_argument_type; +struct _dyn_function_argument_type { + int index; + char *name; + enum dyn_function_argument_meta argumentMeta; + dyn_type *type; + TAILQ_ENTRY(_dyn_function_argument_type) entries; +}; + +static const int OK = 0; +static const int MEM_ERROR = 1; +static const int PARSE_ERROR = 2; +static const int ERROR = 2; + +DFI_SETUP_LOG(dynFunction) + +static int dynFunction_initCif(dyn_function_type *dynFunc); +static int dynFunction_parseDescriptor(dyn_function_type *dynFunc, FILE *descriptor); +static void dynFunction_ffiBind(ffi_cif *cif, void *ret, void *args[], void *userData); + +extern ffi_type * dynType_ffiType(dyn_type *type); + +int dynFunction_parse(FILE *descriptor, struct types_head *refTypes, dyn_function_type **out) { + int status = OK; + dyn_function_type *dynFunc = NULL; + LOG_DEBUG("Creating dyn function", descriptor); + + dynFunc = calloc(1, sizeof(*dynFunc)); + + if (dynFunc != NULL) { + TAILQ_INIT(&dynFunc->arguments); + dynFunc->refTypes = refTypes; + status = dynFunction_parseDescriptor(dynFunc, descriptor); + if (status == 0) { + int rc = dynFunction_initCif(dynFunc); + if (rc != 0) { + LOG_ERROR("Error initializing cif"); + status = ERROR; + } + } + } else { + LOG_ERROR("Error allocationg memory for dyn functipn\n"); + status = MEM_ERROR; + } + + if (status == OK) { + dyn_function_argument_type *arg = NULL; + TAILQ_FOREACH(arg, &dynFunc->arguments, entries) { + const char *meta = dynType_getMetaInfo(arg->type, "am"); + if (meta == NULL) { + arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__STD; + } else if (strcmp(meta, "handle") == 0) { + arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__HANDLE; + } else if (strcmp(meta, "pre") == 0) { + arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__PRE_ALLOCATED_OUTPUT; + } else if (strcmp(meta, "out") == 0) { + arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__OUTPUT; + } else { + LOG_WARNING("unknown argument meta '%s' encountered", meta); + arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__STD; + } + } + } + + if (status == OK) { + *out = dynFunc; + } else { + if (dynFunc != NULL) { + dynFunction_destroy(dynFunc); + } + + } + + return status; +} + +int dynFunction_parseWithStr(const char *descriptor, struct types_head *refTypes, dyn_function_type **out) { + int status = OK; + FILE *stream = fmemopen((char *)descriptor, strlen(descriptor), "r"); + if (stream != NULL) { + status = dynFunction_parse(stream, refTypes, out); + fclose(stream); + } else { + status = MEM_ERROR; + LOG_ERROR("Error creating mem stream for descriptor string. %s", strerror(errno)); + } + return status; +} + +static int dynFunction_parseDescriptor(dyn_function_type *dynFunc, FILE *descriptor) { + int status = OK; + char *name = NULL; + + status = dynCommon_parseName(descriptor, &name); + + if (status == OK) { + dynFunc->name = name; + } + + if (status == OK) { + int c = fgetc(descriptor); + if ( c != '(') { + status = PARSE_ERROR; + LOG_ERROR("Expected '(' token got '%c'", c); + } + } + + int nextChar = fgetc(descriptor); + int index = 0; + dyn_type *type = NULL; + char argName[32]; + while (nextChar != ')' && status == 0) { + ungetc(nextChar, descriptor); + type = NULL; + + dyn_function_argument_type *arg = NULL; + + status = dynType_parse(descriptor, NULL, dynFunc->refTypes, &type); + if (status == OK) { + arg = calloc(1, sizeof(*arg)); + if (arg != NULL) { + arg->index = index; + arg->type = type; + snprintf(argName, 32, "arg%04i", index); + arg->name = strdup(argName); + + index += 1; + } else { + LOG_ERROR("Error allocating memory"); + status = MEM_ERROR; + } + } + + if (status == OK) { + TAILQ_INSERT_TAIL(&dynFunc->arguments, arg, entries); + } + + nextChar = fgetc(descriptor); + } + + if (status == 0) { + status = dynType_parse(descriptor, NULL, dynFunc->refTypes, &dynFunc->funcReturn); + } + + return status; +} + +enum dyn_function_argument_meta dynFunction_argumentMetaForIndex(dyn_function_type *dynFunc, int argumentNr) { + enum dyn_function_argument_meta result = 0; + dyn_function_argument_type *arg = NULL; + int index = 0; + TAILQ_FOREACH(arg, &dynFunc->arguments, entries) { + if (index == argumentNr) { + result = arg->argumentMeta; + break; + } + index += 1; + } + return result; +} + + +static int dynFunction_initCif(dyn_function_type *dynFunc) { + int status = 0; + + int count = 0; + dyn_function_argument_type *entry = NULL; + TAILQ_FOREACH(entry, &dynFunc->arguments, entries) { + count +=1; + } + + dynFunc->ffiArguments = calloc(count, sizeof(ffi_type*)); + + TAILQ_FOREACH(entry, &dynFunc->arguments, entries) { + dynFunc->ffiArguments[entry->index] = dynType_ffiType(entry->type); + } + + ffi_type **args = dynFunc->ffiArguments; + ffi_type *returnType = dynType_ffiType(dynFunc->funcReturn); + + int ffiResult = ffi_prep_cif(&dynFunc->cif, FFI_DEFAULT_ABI, count, returnType, args); + if (ffiResult != FFI_OK) { + status = 1; + } + + return status; +} + +void dynFunction_destroy(dyn_function_type *dynFunc) { + if (dynFunc != NULL) { + if (dynFunc->funcReturn != NULL) { + dynType_destroy(dynFunc->funcReturn); + } + if (dynFunc->ffiClosure != NULL) { + ffi_closure_free(dynFunc->ffiClosure); + } + if (dynFunc->name != NULL) { + free(dynFunc->name); + } + if (dynFunc->ffiArguments != NULL) { + free(dynFunc->ffiArguments); + } + + dyn_function_argument_type *entry = NULL; + dyn_function_argument_type *tmp = NULL; + entry = TAILQ_FIRST(&dynFunc->arguments); + while (entry != NULL) { + if (entry->name != NULL) { + free(entry->name); + } + dynType_destroy(entry->type); + tmp = entry; + entry = TAILQ_NEXT(entry, entries); + free(tmp); + } + + free(dynFunc); + } +} + +int dynFunction_call(dyn_function_type *dynFunc, void(*fn)(void), void *returnValue, void **argValues) { + ffi_call(&dynFunc->cif, fn, returnValue, argValues); + return 0; +} + +static void dynFunction_ffiBind(ffi_cif *cif, void *ret, void *args[], void *userData) { + dyn_function_type *dynFunc = userData; + dynFunc->bind(dynFunc->userData, args, ret); +} + +int dynFunction_createClosure(dyn_function_type *dynFunc, void (*bind)(void *, void **, void*), void *userData, void(**out)(void)) { + int status = 0; + void (*fn)(void); + dynFunc->ffiClosure = ffi_closure_alloc(sizeof(ffi_closure), (void **)&fn); + if (dynFunc->ffiClosure != NULL) { + int rc = ffi_prep_closure_loc(dynFunc->ffiClosure, &dynFunc->cif, dynFunction_ffiBind, dynFunc, fn); + if (rc != FFI_OK) { + status = 1; + } + } else { + status = 2; + } + + if (status == 0) { + dynFunc->userData = userData; + dynFunc->bind = bind; + dynFunc->fn = fn; + *out =fn; + } + + return status; +} + +int dynFunction_getFnPointer(dyn_function_type *dynFunc, void (**fn)(void)) { + int status = 0; + if (dynFunc != NULL && dynFunc->fn != NULL) { + (*fn) = dynFunc->fn; + } else { + status = 1; + } + return status; +} + +int dynFunction_nrOfArguments(dyn_function_type *dynFunc) { + int count = 0; + dyn_function_argument_type *entry = NULL; + TAILQ_FOREACH(entry, &dynFunc->arguments, entries) { + count += 1; + } + return count; +} + +dyn_type *dynFunction_argumentTypeForIndex(dyn_function_type *dynFunc, int argumentNr) { + dyn_type *result = NULL; + int index = 0; + dyn_function_argument_type *entry = NULL; + TAILQ_FOREACH(entry, &dynFunc->arguments, entries) { + if (index == argumentNr) { + result = entry->type; + break; + } + index +=1; + } + return result; +} + +dyn_type * dynFunction_returnType(dyn_function_type *dynFunction) { + return dynFunction->funcReturn; +} + http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/dfi/src/dyn_interface.c ---------------------------------------------------------------------- diff --git a/dfi/src/dyn_interface.c b/dfi/src/dyn_interface.c new file mode 100644 index 0000000..63aafac --- /dev/null +++ b/dfi/src/dyn_interface.c @@ -0,0 +1,444 @@ +/** + *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_interface.h" + +#include <stdlib.h> +#include <string.h> + +#include "dyn_common.h" +#include "dyn_type.h" +#include "dyn_interface.h" + +DFI_SETUP_LOG(dynInterface); + +struct _dyn_interface_type { + struct namvals_head header; + struct namvals_head annotations; + struct types_head types; + struct methods_head methods; + version_pt version; +}; + +static const int OK = 0; +static const int ERROR = 1; + +static int dynInterface_parseSection(dyn_interface_type *intf, FILE *stream); +static int dynInterface_parseAnnotations(dyn_interface_type *intf, FILE *stream); +static int dynInterface_parseTypes(dyn_interface_type *intf, FILE *stream); +static int dynInterface_parseMethods(dyn_interface_type *intf, FILE *stream); +static int dynInterface_parseHeader(dyn_interface_type *intf, FILE *stream); +static int dynInterface_parseNameValueSection(dyn_interface_type *intf, FILE *stream, struct namvals_head *head); +static int dynInterface_checkInterface(dyn_interface_type *intf); +static int dynInterface_getEntryForHead(struct namvals_head *head, const char *name, char **value); + +int dynInterface_parse(FILE *descriptor, dyn_interface_type **out) { + int status = OK; + + dyn_interface_type *intf = calloc(1, sizeof(*intf)); + if (intf != NULL) { + TAILQ_INIT(&intf->header); + TAILQ_INIT(&intf->annotations); + TAILQ_INIT(&intf->types); + TAILQ_INIT(&intf->methods); + + char peek = (char)fgetc(descriptor); + while (peek == ':') { + ungetc(peek, descriptor); + status = dynInterface_parseSection(intf, descriptor); + if (status == OK) { + peek = (char)fgetc(descriptor); + } else { + break; + } + } + + if (status == OK) { + status = dynCommon_eatChar(descriptor, EOF); + } + + if (status == OK) { + status = dynInterface_checkInterface(intf); + } + + if(status==OK){ /* We are sure that version field is present in the header */ + char* version=NULL; + dynInterface_getVersionString(intf,&version); + if(version!=NULL){ + status = (version_createVersionFromString(version,&(intf->version)) == CELIX_SUCCESS)?OK:ERROR; + } + if(status==ERROR){ + LOG_ERROR("Invalid version (%s) in parsed descriptor\n",version); + } + } + } else { + status = ERROR; + LOG_ERROR("Error allocating memory for dynamic interface\n"); + } + + if (status == OK) { + *out = intf; + } else if (intf != NULL) { + dynInterface_destroy(intf); + } + return status; +} + +static int dynInterface_checkInterface(dyn_interface_type *intf) { + int status = OK; + + //check header section + if (status == OK) { + bool foundType = false; + bool foundVersion = false; + bool foundName = false; + struct namval_entry *entry = NULL; + TAILQ_FOREACH(entry, &intf->header, entries) { + if (strcmp(entry->name, "type") == 0) { + foundType = true; + } else if (strcmp(entry->name, "version") == 0) { + foundVersion = true; + } else if (strcmp(entry->name, "name") == 0) { + foundName = true; + } + } + + if (!foundType || !foundVersion || !foundName) { + status = ERROR; + LOG_ERROR("Parse Error. There must be a header section with a type, version and name entry"); + } + + struct method_entry *mEntry = NULL; + TAILQ_FOREACH(mEntry, &intf->methods, entries) { + dyn_type *type = dynFunction_returnType(mEntry->dynFunc); + int descriptor = dynType_descriptorType(type); + if (descriptor != 'N') { + status = ERROR; + LOG_ERROR("Parse Error. Only method with a return type 'N' (native int) are supported. Got return type '%c'\n", descriptor); + break; + } + } + } + + return status; +} + +static int dynInterface_parseSection(dyn_interface_type *intf, FILE *stream) { + int status = OK; + char *sectionName = NULL; + + status = dynCommon_eatChar(stream, ':'); + + if (status == OK) { + status = dynCommon_parseName(stream, §ionName); + } + + if (status == OK) { + status = dynCommon_eatChar(stream, '\n'); + } + + if (status == OK) { + if (strcmp("header", sectionName) == 0) { + status = dynInterface_parseHeader(intf, stream); + } else if (strcmp("annotations", sectionName) == 0) { + status = dynInterface_parseAnnotations(intf, stream); + } else if (strcmp("types", sectionName) == 0) { + status = dynInterface_parseTypes(intf, stream); + } else if (strcmp("methods", sectionName) == 0) { + status = dynInterface_parseMethods(intf, stream); + } else { + status = ERROR; + LOG_ERROR("unsupported section '%s'", sectionName); + } + } + + if (sectionName != NULL) { + free(sectionName); + } + + return status; +} + +static int dynInterface_parseHeader(dyn_interface_type *intf, FILE *stream) { + return dynInterface_parseNameValueSection(intf, stream, &intf->header); +} + +static int dynInterface_parseAnnotations(dyn_interface_type *intf, FILE *stream) { + return dynInterface_parseNameValueSection(intf, stream, &intf->annotations); +} + +static int dynInterface_parseNameValueSection(dyn_interface_type *intf, FILE *stream, struct namvals_head *head) { + int status = OK; + + int peek = fgetc(stream); + while (peek != ':' && peek != EOF) { + ungetc(peek, stream); + + char *name; + char *value; + status = dynCommon_parseNameValue(stream, &name, &value); + + if (status == OK) { + status = dynCommon_eatChar(stream, '\n'); + } + + struct namval_entry *entry = NULL; + if (status == OK) { + entry = calloc(1, sizeof(*entry)); + if (entry != NULL) { + entry->name = name; + entry->value = value; + TAILQ_INSERT_TAIL(head, entry, entries); + } else { + status = ERROR; + LOG_ERROR("Error allocating memory for namval entry"); + } + } + + if (status != OK) { + if (name != NULL) { + free(name); + } + if (value != NULL) { + free(value); + } + break; + } + peek = fgetc(stream); + } + ungetc(peek, stream); + + return status; +} + +static int dynInterface_parseTypes(dyn_interface_type *intf, FILE *stream) { + int status = OK; + + //expected input (Name)=<Type>\n + int peek = fgetc(stream); + while (peek != ':' && peek != EOF) { + ungetc(peek, stream); + + char *name; + status = dynCommon_parseName(stream, &name); + + if (status == OK) { + status = dynCommon_eatChar(stream, '='); + } + + dyn_type *type = NULL; + if (status == OK) { + dynType_parse(stream, name, &intf->types, &type); + } + if (name != NULL) { + free(name); + } + + if (status == OK) { + status = dynCommon_eatChar(stream, '\n'); + } + + struct type_entry *entry = NULL; + if (status == OK) { + entry = calloc(1, sizeof(*entry)); + if (entry != NULL) { + entry->type = type; + TAILQ_INSERT_TAIL(&intf->types, entry, entries); + } else { + status = ERROR; + LOG_ERROR("Error allocating memory for type entry"); + } + } + + if (status != OK) { + if (type != NULL) { + dynType_destroy(type); + } + break; + } + peek = fgetc(stream); + } + ungetc(peek, stream); + + return status; +} + +static int dynInterface_parseMethods(dyn_interface_type *intf, FILE *stream) { + int status = OK; + + //expected input (Name)=<Method>\n + int peek = fgetc(stream); + int index = 0; + while (peek != ':' && peek != EOF) { + ungetc(peek, stream); + + char *id; + status = dynCommon_parseNameAlsoAccept(stream, ".();[{}/", &id); + + if (status == OK) { + status = dynCommon_eatChar(stream, '='); + } + + + dyn_function_type *func = NULL; + if (status == OK) { + status = dynFunction_parse(stream, &intf->types, &func); + } + + if (status == OK) { + status = dynCommon_eatChar(stream, '\n'); + } + + struct method_entry *entry = NULL; + if (status == OK) { + entry = calloc(1, sizeof(*entry)); + if (entry != NULL) { + entry->index = index++; + entry->id = id; + entry->dynFunc = func; + entry->name = strndup(id, 1024); + if (entry->name != NULL) { + int i; + for (i = 0; i < 1024; i += 1) { + if (entry->name[i] == '\0') { + break; + } else if (entry->name[i] == '(') { + entry->name[i] = '\0'; + break; + } + } + } + TAILQ_INSERT_TAIL(&intf->methods, entry, entries); + } else { + status = ERROR; + LOG_ERROR("Error allocating memory for method entry"); + } + } + + if (status != OK) { + if (id != NULL) { + free(id); + } + if (func != NULL) { + dynFunction_destroy(func); + //TODO free strIdentier, name + } + break; + } + peek = fgetc(stream); + } + ungetc(peek, stream); + + return status; +} + +void dynInterface_destroy(dyn_interface_type *intf) { + if (intf != NULL) { + dynCommon_clearNamValHead(&intf->header); + dynCommon_clearNamValHead(&intf->annotations); + + struct method_entry *mInfo = TAILQ_FIRST(&intf->methods); + while (mInfo != NULL) { + struct method_entry *mTmp = mInfo; + mInfo = TAILQ_NEXT(mInfo, entries); + + if (mTmp->id != NULL) { + free(mTmp->id); + } + if (mTmp->name != NULL) { + free(mTmp->name); + } + if (mTmp->dynFunc != NULL) { + dynFunction_destroy(mTmp->dynFunc); + } + free(mTmp); + } + + struct type_entry *tInfo = TAILQ_FIRST(&intf->types); + while (tInfo != NULL) { + struct type_entry *tmp = tInfo; + tInfo = TAILQ_NEXT(tInfo, entries); + dynType_destroy(tmp->type); + free(tmp); + } + + if(intf->version!=NULL){ + version_destroy(intf->version); + } + + free(intf); + } +} + +int dynInterface_getName(dyn_interface_type *intf, char **out) { + return dynInterface_getEntryForHead(&intf->header, "name", out); +} + +int dynInterface_getVersion(dyn_interface_type* intf , version_pt* version){ + *version = intf->version; + if(*version==NULL){ + return ERROR; + } + return OK; +} + +int dynInterface_getVersionString(dyn_interface_type *intf, char **version) { + return dynInterface_getEntryForHead(&intf->header, "version", version); +} + +int dynInterface_getHeaderEntry(dyn_interface_type *intf, const char *name, char **value) { + return dynInterface_getEntryForHead(&intf->header, name, value); +} + +int dynInterface_getAnnotationEntry(dyn_interface_type *intf, const char *name, char **value) { + return dynInterface_getEntryForHead(&intf->annotations, name, value); +} + +static int dynInterface_getEntryForHead(struct namvals_head *head, const char *name, char **out) { + int status = OK; + char *value = NULL; + struct namval_entry *entry = NULL; + TAILQ_FOREACH(entry, head, entries) { + if (strcmp(name, entry->name) == 0) { + value = entry->value; + break; + } + } + if (value != NULL) { + *out = value; + } else { + status = ERROR; + LOG_WARNING("Cannot find '%s' in list", name); + } + return status; +} + +int dynInterface_methods(dyn_interface_type *intf, struct methods_head **list) { + int status = OK; + *list = &intf->methods; + return status; +} + +int dynInterface_nrOfMethods(dyn_interface_type *intf) { + int count = 0; + struct method_entry *entry = NULL; + TAILQ_FOREACH(entry, &intf->methods, entries) { + count +=1; + } + return count; +} http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/dfi/src/dyn_message.c ---------------------------------------------------------------------- diff --git a/dfi/src/dyn_message.c b/dfi/src/dyn_message.c new file mode 100644 index 0000000..652be83 --- /dev/null +++ b/dfi/src/dyn_message.c @@ -0,0 +1,358 @@ +/** + *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_message.h" + +#include <stdlib.h> +#include <string.h> + +#include "dyn_common.h" +#include "dyn_type.h" + +DFI_SETUP_LOG(dynMessage); + +struct _dyn_message_type { + struct namvals_head header; + struct namvals_head annotations; + struct types_head types; + dyn_type *msgType; + version_pt msgVersion; +}; + +static const int OK = 0; +static const int ERROR = 1; + +static int dynMessage_parseSection(dyn_message_type *msg, FILE *stream); +static int dynMessage_parseAnnotations(dyn_message_type *msg, FILE *stream); +static int dynMessage_parseTypes(dyn_message_type *msg, FILE *stream); +static int dynMessage_parseMessage(dyn_message_type *msg, FILE *stream); +static int dynMessage_parseHeader(dyn_message_type *msg, FILE *stream); +static int dynMessage_parseNameValueSection(dyn_message_type *msg, FILE *stream, struct namvals_head *head); +static int dynMessage_checkMessage(dyn_message_type *msg); +static int dynMessage_getEntryForHead(struct namvals_head *head, const char *name, char **value); + +int dynMessage_parse(FILE *descriptor, dyn_message_type **out) { + int status = OK; + + dyn_message_type *msg = calloc(1, sizeof(*msg)); + if (msg != NULL) { + TAILQ_INIT(&msg->header); + TAILQ_INIT(&msg->annotations); + TAILQ_INIT(&msg->types); + + char peek = (char)fgetc(descriptor); + while (peek == ':') { + ungetc(peek, descriptor); + status = dynMessage_parseSection(msg, descriptor); + if (status == OK) { + peek = (char)fgetc(descriptor); + } else { + break; + } + } + + if (status == OK) { + status = dynCommon_eatChar(descriptor, EOF); + } + + if (status == OK) { + status = dynMessage_checkMessage(msg); + } + + if(status==OK){ /* We are sure that version field is present in the header */ + char* version=NULL; + dynMessage_getVersionString(msg,&version); + if(version!=NULL){ + status = (version_createVersionFromString(version,&(msg->msgVersion)) == CELIX_SUCCESS)?OK:ERROR; + } + if(status==ERROR){ + LOG_ERROR("Invalid version (%s) in parsed descriptor\n",version); + } + } + + } else { + status = ERROR; + LOG_ERROR("Error allocating memory for dynamic message\n"); + } + + if (status == OK) { + *out = msg; + } else if (msg != NULL) { + LOG_ERROR("Error parsing msg\n"); + dynMessage_destroy(msg); + } + return status; +} + +static int dynMessage_checkMessage(dyn_message_type *msg) { + int status = OK; + + //check header section + if (status == OK) { + bool foundType = false; + bool foundVersion = false; + bool foundName = false; + struct namval_entry *entry = NULL; + TAILQ_FOREACH(entry, &msg->header, entries) { + if (strcmp(entry->name, "type") == 0) { + foundType = true; + } else if (strcmp(entry->name, "version") == 0) { + foundVersion = true; + } else if (strcmp(entry->name, "name") == 0) { + foundName = true; + } + } + + if (!foundType || !foundVersion || !foundName) { + status = ERROR; + LOG_ERROR("Parse Error. There must be a header section with a type, version and name entry"); + } + } + + return status; +} + +static int dynMessage_parseSection(dyn_message_type *msg, FILE *stream) { + int status; + char *sectionName = NULL; + + status = dynCommon_eatChar(stream, ':'); + + if (status == OK) { + status = dynCommon_parseName(stream, §ionName); + } + + if (status == OK) { + status = dynCommon_eatChar(stream, '\n'); + } + + if (status == OK) { + if (strcmp("header", sectionName) == 0) { + status = dynMessage_parseHeader(msg, stream); + } else if (strcmp("annotations", sectionName) == 0) { + status = dynMessage_parseAnnotations(msg, stream); + } else if (strcmp("types", sectionName) == 0) { + status = dynMessage_parseTypes(msg, stream); + } else if (strcmp("message", sectionName) == 0) { + status = dynMessage_parseMessage(msg, stream); + } else { + status = ERROR; + LOG_ERROR("unsupported section '%s'", sectionName); + } + } + + if (sectionName != NULL) { + free(sectionName); + } + + return status; +} + +static int dynMessage_parseHeader(dyn_message_type *msg, FILE *stream) { + return dynMessage_parseNameValueSection(msg, stream, &msg->header); +} + +static int dynMessage_parseAnnotations(dyn_message_type *msg, FILE *stream) { + return dynMessage_parseNameValueSection(msg, stream, &msg->annotations); +} + +static int dynMessage_parseNameValueSection(dyn_message_type *msg, FILE *stream, struct namvals_head *head) { + int status = OK; + + int peek = fgetc(stream); + while (peek != ':' && peek != EOF) { + ungetc(peek, stream); + + char *name; + char *value; + status = dynCommon_parseNameValue(stream, &name, &value); + + if (status == OK) { + status = dynCommon_eatChar(stream, '\n'); + } + + struct namval_entry *entry = NULL; + if (status == OK) { + entry = calloc(1, sizeof(*entry)); + if (entry != NULL) { + entry->name = name; + entry->value = value; + TAILQ_INSERT_TAIL(head, entry, entries); + } else { + status = ERROR; + LOG_ERROR("Error allocating memory for namval entry"); + } + } + + if (status != OK) { + if (name != NULL) { + free(name); + } + if (value != NULL) { + free(value); + } + break; + } + peek = fgetc(stream); + } + ungetc(peek, stream); + + return status; +} + +static int dynMessage_parseTypes(dyn_message_type *msg, FILE *stream) { + int status = OK; + + //expected input (Name)=<Type>\n + int peek = fgetc(stream); + while (peek != ':' && peek != EOF) { + ungetc(peek, stream); + + char *name = NULL; + status = dynCommon_parseName(stream, &name); + + if (status == OK) { + status = dynCommon_eatChar(stream, '='); + } + + dyn_type *type = NULL; + if (status == OK) { + status = dynType_parse(stream, name, &msg->types, &type); + } + + if (status == OK) { + status = dynCommon_eatChar(stream, '\n'); + } + + struct type_entry *entry = NULL; + if (status == OK) { + entry = calloc(1, sizeof(*entry)); + if (entry != NULL) { + LOG_DEBUG("Adding type '%s' with pointer %p to types", name, type); + entry->type = type; + TAILQ_INSERT_TAIL(&msg->types, entry, entries); + } else { + status = ERROR; + LOG_ERROR("Error allocating memory for type entry"); + } + } + + if (name != NULL) { + free(name); + } + + if (status != OK) { + if (type != NULL) { + dynType_destroy(type); + } + break; + } + peek = fgetc(stream); + } + ungetc(peek, stream); + + return status; +} + +static int dynMessage_parseMessage(dyn_message_type *msg, FILE *stream) { + int status; + + //expected input <dynType>\n + char *name = NULL; + status = dynMessage_getName(msg, &name); + + if (status == OK) { + status = dynType_parse(stream, name, &(msg->types), &(msg->msgType)); + } + + return status; +} + +void dynMessage_destroy(dyn_message_type *msg) { + if (msg != NULL) { + dynCommon_clearNamValHead(&msg->header); + dynCommon_clearNamValHead(&msg->annotations); + + struct type_entry *tInfo = TAILQ_FIRST(&msg->types); + while (tInfo != NULL) { + struct type_entry *tmp = tInfo; + tInfo = TAILQ_NEXT(tInfo, entries); + dynType_destroy(tmp->type); + free(tmp); + } + + if (msg->msgType != NULL) { + dynType_destroy(msg->msgType); + } + + if(msg->msgVersion != NULL){ + version_destroy(msg->msgVersion); + } + + free(msg); + } +} + +int dynMessage_getName(dyn_message_type *msg, char **out) { + return dynMessage_getEntryForHead(&msg->header, "name", out); +} + +int dynMessage_getVersion(dyn_message_type *msg, version_pt* version){ + *version = msg->msgVersion; + if(*version==NULL){ + return ERROR; + } + return OK; +} + +int dynMessage_getVersionString(dyn_message_type *msg, char **version) { + return dynMessage_getEntryForHead(&msg->header, "version", version); +} + +int dynMessage_getHeaderEntry(dyn_message_type *msg, const char *name, char **value) { + return dynMessage_getEntryForHead(&msg->header, name, value); +} + +int dynMessage_getAnnotationEntry(dyn_message_type *msg, const char *name, char **value) { + return dynMessage_getEntryForHead(&msg->annotations, name, value); +} + +static int dynMessage_getEntryForHead(struct namvals_head *head, const char *name, char **out) { + int status = OK; + char *value = NULL; + struct namval_entry *entry = NULL; + TAILQ_FOREACH(entry, head, entries) { + if (strcmp(name, entry->name) == 0) { + value = entry->value; + break; + } + } + if (value != NULL) { + *out = value; + } else { + status = ERROR; + LOG_WARNING("Cannot find '%s' in list", name); + } + return status; +} + +int dynMessage_getMessageType(dyn_message_type *msg, dyn_type **type) { + int status = OK; + *type = msg->msgType; + return status; +} http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/dfi/src/dyn_type.c ---------------------------------------------------------------------- diff --git a/dfi/src/dyn_type.c b/dfi/src/dyn_type.c new file mode 100644 index 0000000..4fc79ff --- /dev/null +++ b/dfi/src/dyn_type.c @@ -0,0 +1,1160 @@ +/** + *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 <ffi.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); +ffi_type * dynType_ffiType(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 { + free(entry); + status = MEM_ERROR; + LOG_ERROR("Error allocating memory for type"); + } + + if (status != OK) { + break; + } + + c = fgetc(stream); + } + + + if (status == OK) { + 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; + if (status == OK) { + 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; + LOG_ERROR("Error allocating memory for elements") + } + } + + if (status == OK) { + type->complex.types = calloc(count, sizeof(dyn_type *)); + if (type->complex.types != 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); + assert(index >= 0); + 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 OK; +} + +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) { + if (type->ref.ref == NULL) { + LOG_ERROR("Error. Ref for %s is not (yet) initialized", type->name); + return NULL; + } + 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; + char buf[128]; + memset(buf,0,128); + if (name != NULL) { + 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); +} +
