Repository: celix Updated Branches: refs/heads/feature/CELIX-237_rsa-ffi 08b5bc0ca -> 3cc606e8e
CELIX-237: Added dyn_interface implementation. dyn_interface works on top of dyn_type and dyn_function Project: http://git-wip-us.apache.org/repos/asf/celix/repo Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/3cc606e8 Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/3cc606e8 Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/3cc606e8 Branch: refs/heads/feature/CELIX-237_rsa-ffi Commit: 3cc606e8e9837fa7dbc5f471121b66dba8c8c89c Parents: 08b5bc0 Author: Pepijn Noltes <[email protected]> Authored: Sun Jul 12 21:54:31 2015 +0200 Committer: Pepijn Noltes <[email protected]> Committed: Sun Jul 12 21:54:31 2015 +0200 ---------------------------------------------------------------------- .../dynamic_function_interface/CMakeLists.txt | 2 + .../dynamic_function_interface/dyn_common.c | 55 ++++++- .../dynamic_function_interface/dyn_common.h | 4 +- .../dynamic_function_interface/dyn_interface.c | 158 +++++++++++++++++-- .../dynamic_function_interface/dyn_interface.h | 26 +-- .../tst/dyn_interface_tests.cpp | 61 +++++++ 6 files changed, 279 insertions(+), 27 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/celix/blob/3cc606e8/remote_services/dynamic_function_interface/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/remote_services/dynamic_function_interface/CMakeLists.txt b/remote_services/dynamic_function_interface/CMakeLists.txt index 0c69d92..309176f 100644 --- a/remote_services/dynamic_function_interface/CMakeLists.txt +++ b/remote_services/dynamic_function_interface/CMakeLists.txt @@ -35,6 +35,7 @@ target_link_libraries(dfi ${FFI_LIBRARIES} ${JANSSON_LIBRARY}) tst/dyn_type_tests.cpp tst/dyn_function_tests.cpp tst/dyn_closure_tests.cpp + tst/dyn_interface_tests.cpp tst/json_serializer_tests.cpp # tst/avro_descriptor_translator_tests.cpp tst/run_tests.cpp @@ -43,6 +44,7 @@ target_link_libraries(dfi ${FFI_LIBRARIES} ${JANSSON_LIBRARY}) add_custom_target(copy-input COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/schemas schemas + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/descriptors descriptors ) add_dependencies(dfi_tests copy-input) http://git-wip-us.apache.org/repos/asf/celix/blob/3cc606e8/remote_services/dynamic_function_interface/dyn_common.c ---------------------------------------------------------------------- diff --git a/remote_services/dynamic_function_interface/dyn_common.c b/remote_services/dynamic_function_interface/dyn_common.c index c0d5ca0..05844ef 100644 --- a/remote_services/dynamic_function_interface/dyn_common.c +++ b/remote_services/dynamic_function_interface/dyn_common.c @@ -3,6 +3,7 @@ */ #include "dyn_common.h" +#include <stdlib.h> #include <stdio.h> #include <ctype.h> @@ -21,6 +22,7 @@ int dynCommon_parseName(FILE *stream, char **result) { char *buf = NULL; size_t size = 0; + int strLen = 0; FILE *name = open_memstream(&buf, &size); if (name != NULL) { @@ -28,14 +30,65 @@ int dynCommon_parseName(FILE *stream, char **result) { while (isalnum(c) || c == '_') { fputc(c, name); c = getc(stream); + strLen += 1; } fflush(name); fclose(name); - *result = buf; 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"); + free(buf); + } + } + + if (status == OK) { + LOG_DEBUG("Parsed name '%s'", buf); + *result = buf; + } + + return status; +} + +int dynCommon_parseNameValue(FILE *stream, char **outName, char **outValue) { + int status = OK; + char *name = NULL; + char *value = NULL; + + status = dynCommon_parseName(stream, &name); + if (status == OK) { + status = dynCommon_eatChar(stream, '='); + } + if (status == OK) { + status = dynCommon_parseName(stream, &value); //TODO use different more lenient function? + } + + 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; + int c = fgetc(stream); + if (c != expected) { + status = ERROR; + LOG_ERROR("Error parsing, expected token '%c' got '%c'", expected, c); + } return status; } http://git-wip-us.apache.org/repos/asf/celix/blob/3cc606e8/remote_services/dynamic_function_interface/dyn_common.h ---------------------------------------------------------------------- diff --git a/remote_services/dynamic_function_interface/dyn_common.h b/remote_services/dynamic_function_interface/dyn_common.h index 8a9491a..16df6e2 100644 --- a/remote_services/dynamic_function_interface/dyn_common.h +++ b/remote_services/dynamic_function_interface/dyn_common.h @@ -24,8 +24,8 @@ struct _dyn_annotation_type { }; int dynCommon_parseName(FILE *stream, char **result); -//TODO int dynCommon_parseNameValue(FILE *stream, char **name, char **value); -//TODO int dynCommon_parseAnnotation(FILE *stream, +int dynCommon_parseNameValue(FILE *stream, char **name, char **value); +int dynCommon_eatChar(FILE *stream, int c); #endif http://git-wip-us.apache.org/repos/asf/celix/blob/3cc606e8/remote_services/dynamic_function_interface/dyn_interface.c ---------------------------------------------------------------------- diff --git a/remote_services/dynamic_function_interface/dyn_interface.c b/remote_services/dynamic_function_interface/dyn_interface.c index 1fbb831..a563eab 100644 --- a/remote_services/dynamic_function_interface/dyn_interface.c +++ b/remote_services/dynamic_function_interface/dyn_interface.c @@ -6,31 +6,139 @@ #include <stdlib.h> #include <string.h> -DFI_SETUP_LOG(dynInterface) +#include "dyn_common.h" +#include "dyn_type.h" +#include "dyn_interface.h" -int dynInterface_create(const char *name, dyn_interface_type **out) { - int status = 0; - dyn_interface_type *inft = calloc(1, sizeof(*inft)); - if (inft != NULL) { - inft->name = strdup(name); - } - if (inft == NULL || inft->name == NULL) { - status = 1; +DFI_SETUP_LOG(dynInterface); + +const int OK = 0; +const int ERROR = 1; + +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); + +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->annotations); + TAILQ_INIT(&intf->types); + TAILQ_INIT(&intf->methods); + + status = dynInterface_parseAnnotations(intf, descriptor); + if (status == OK) { + status =dynInterface_parseTypes(intf, descriptor); + } + if (status == OK) { + status = dynInterface_parseMethods(intf, descriptor); + } + } else { + status = ERROR; LOG_ERROR("Error allocating memory for dynamic interface\n"); } - if (status == 0) { - TAILQ_INIT(&inft->types); - TAILQ_INIT(&inft->methods); + if (status == OK) { + *out = intf; + } else if (intf != NULL) { + dynInterface_destroy(intf); } - *out = inft; + return status; +} + +static int dynInterface_parseAnnotations(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("annotations", sectionName) == 0) { + LOG_DEBUG("Parsed annotations section header"); + } else { + status = ERROR; + LOG_ERROR("Expected annotations section, got '%s'", sectionName); + } + } + + if (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'); + } + + if (status == OK) { + interface_namval_type *entry = calloc(1, sizeof(*entry)); + if (entry != NULL) { + entry->name = name; + entry->value = value; + TAILQ_INSERT_TAIL(&intf->annotations, 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; + //TODO implement -> extract section parse part from parseAnnotations first? + return status; +} + +static int dynInterface_parseMethods(dyn_interface_type *intf, FILE *stream) { + int status = OK; + //TODO refactor return status; } void dynInterface_destroy(dyn_interface_type *intf) { if (intf != NULL) { - if (intf->name != NULL) { - free(intf->name); + interface_namval_type *nTmp = NULL; + interface_namval_type *nEntry = TAILQ_FIRST(&intf->annotations); + while (nEntry != NULL) { + nTmp = nEntry; + nEntry = TAILQ_NEXT(nEntry, entries); + if (nTmp->name != NULL) { + free(nTmp->name); + } + if (nTmp->value != NULL) { + free(nTmp->value); + } + free(nTmp); } interface_type_type *tmp = NULL; @@ -68,3 +176,23 @@ void dynInterface_destroy(dyn_interface_type *intf) { } } +//TODO refactor using a dynInterface_findAnnotation method +int dynInterface_getName(dyn_interface_type *intf, char **out) { + int status = OK; + char *name = NULL; + interface_namval_type *entry = NULL; + TAILQ_FOREACH(entry, &intf->annotations, entries) { + if (strcmp("name", entry->name) == 0) { + name = entry->value; + break; + } + } + + if (name != NULL) { + *out = name; + } else { + status = ERROR; + LOG_WARNING("Cannot find 'name' in dyn interface annotations"); + } + return status; +} http://git-wip-us.apache.org/repos/asf/celix/blob/3cc606e8/remote_services/dynamic_function_interface/dyn_interface.h ---------------------------------------------------------------------- diff --git a/remote_services/dynamic_function_interface/dyn_interface.h b/remote_services/dynamic_function_interface/dyn_interface.h index 77eefb8..a574496 100644 --- a/remote_services/dynamic_function_interface/dyn_interface.h +++ b/remote_services/dynamic_function_interface/dyn_interface.h @@ -10,23 +10,29 @@ DFI_SETUP_LOG_HEADER(dynInterface); +/* Description string + * + * Descriptor = [Section]* + * Section = SecionHeader | Body + * SectionHeader = ':' (Name) + * SectionBody = subDescriptor '\n\ + * + * expected sections: header, types & mehods + */ + typedef struct _dyn_interface_type dyn_interface_type; struct _dyn_interface_type { - char *name; - int versionMajor; - int versionMinor; - int versionMicro; - TAILQ_HEAD(, _interface_annotation_type) annotations; + TAILQ_HEAD(, _interface_namval_type) annotations; TAILQ_HEAD(, _interface_type_type) types; TAILQ_HEAD(, _interface_method_type) methods; }; -typedef struct _interface_annotation_type interface_annotation_type; -struct _interface_annotation_type { +typedef struct _interface_namval_type interface_namval_type; +struct _interface_namval_type { char *name; char *value; - TAILQ_ENTRY(_interface_annotation_type) entries; + TAILQ_ENTRY(_interface_namval_type) entries; }; typedef struct _interface_method_type interface_method_type; @@ -46,8 +52,10 @@ struct _interface_type_type { TAILQ_ENTRY(_interface_type_type) entries; }; -int dynInterface_parse(const FILE *descriptor, dyn_interface_type **out); +int dynInterface_parse(FILE *descriptor, dyn_interface_type **out); void dynInterface_destroy(dyn_interface_type *intf); +int dynInterface_getName(dyn_interface_type *intf, char **name); + #endif http://git-wip-us.apache.org/repos/asf/celix/blob/3cc606e8/remote_services/dynamic_function_interface/tst/dyn_interface_tests.cpp ---------------------------------------------------------------------- diff --git a/remote_services/dynamic_function_interface/tst/dyn_interface_tests.cpp b/remote_services/dynamic_function_interface/tst/dyn_interface_tests.cpp new file mode 100644 index 0000000..68dae7a --- /dev/null +++ b/remote_services/dynamic_function_interface/tst/dyn_interface_tests.cpp @@ -0,0 +1,61 @@ +/* + * Licensed under Apache License v2. See LICENSE for more information. + */ +#include <CppUTest/TestHarness.h> +#include "CppUTest/CommandLineTestRunner.h" +extern "C" { + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> + +#include "dyn_common.h" +#include "dyn_interface.h" + +#if defined(BSD) || defined(__APPLE__) +#include "open_memstream.h" +#include "fmemopen.h" +#endif + + static void stdLog(void *handle, int level, const char *file, int line, const char *msg, ...) { + va_list ap; + const char *levels[5] = {"NIL", "ERROR", "WARNING", "INFO", "DEBUG"}; + fprintf(stderr, "%s: FILE:%s, LINE:%i, MSG:",levels[level], file, line); + va_start(ap, msg); + vfprintf(stderr, msg, ap); + fprintf(stderr, "\n"); + } + + static void test1(void) { + int status = 0; + dyn_interface_type *dynIntf = NULL; + FILE *desc = fopen("descriptors/example1.descriptor", "r"); + assert(desc != NULL); + status = dynInterface_parse(desc, &dynIntf); + CHECK_EQUAL(0, status); + + char *name = NULL; + status = dynInterface_getName(dynIntf, &name); + CHECK_EQUAL(0, status); + STRCMP_EQUAL("calculator", name); + + dynInterface_destroy(dynIntf); + } + +} + + +TEST_GROUP(DynInterfaceTests) { + void setup() { + dynCommon_logSetup(stdLog, NULL, 4); + dynType_logSetup(stdLog, NULL, 4); + dynFunction_logSetup(stdLog, NULL, 4); + } +}; + +TEST(DynInterfaceTests, test1) { + test1(); +}
