summaryrefslogtreecommitdiff
path: root/src/nsgenbind-ast.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nsgenbind-ast.c')
-rw-r--r--src/nsgenbind-ast.c759
1 files changed, 402 insertions, 357 deletions
diff --git a/src/nsgenbind-ast.c b/src/nsgenbind-ast.c
index 2f630b7..49477cf 100644
--- a/src/nsgenbind-ast.c
+++ b/src/nsgenbind-ast.c
@@ -14,7 +14,9 @@
#include <stdlib.h>
#include <errno.h>
#include <string.h>
+#include <stdarg.h>
+#include "utils.h"
#include "nsgenbind-ast.h"
#include "options.h"
@@ -26,478 +28,521 @@ extern int nsgenbind_parse(struct genbind_node **genbind_ast);
/* terminal nodes have a value only */
struct genbind_node {
- enum genbind_node_type type;
- struct genbind_node *l;
- union {
- void *value;
- struct genbind_node *node;
- char *text;
- int number; /* node data is an integer */
- } r;
+ enum genbind_node_type type;
+ struct genbind_node *l;
+ union {
+ void *value;
+ struct genbind_node *node;
+ char *text;
+ int number; /* node data is an integer */
+ } r;
};
char *genbind_strapp(char *a, char *b)
{
- char *fullstr;
- int fulllen;
- fulllen = strlen(a) + strlen(b) + 1;
- fullstr = malloc(fulllen);
- snprintf(fullstr, fulllen, "%s%s", a, b);
- free(a);
- free(b);
- return fullstr;
+ char *fullstr;
+ int fulllen;
+ fulllen = strlen(a) + strlen(b) + 1;
+ fullstr = malloc(fulllen);
+ snprintf(fullstr, fulllen, "%s%s", a, b);
+ free(a);
+ free(b);
+ return fullstr;
}
struct genbind_node *
genbind_node_link(struct genbind_node *tgt, struct genbind_node *src)
{
- tgt->l = src;
- return tgt;
+ tgt->l = src;
+ return tgt;
}
struct genbind_node *
genbind_new_node(enum genbind_node_type type, struct genbind_node *l, void *r)
{
- struct genbind_node *nn;
- nn = calloc(1, sizeof(struct genbind_node));
- nn->type = type;
- nn->l = l;
- nn->r.value = r;
- return nn;
+ struct genbind_node *nn;
+ nn = calloc(1, sizeof(struct genbind_node));
+ nn->type = type;
+ nn->l = l;
+ nn->r.value = r;
+ return nn;
}
/* exported interface defined in nsgenbind-ast.h */
int
genbind_node_foreach_type(struct genbind_node *node,
- enum genbind_node_type type,
- genbind_callback_t *cb,
- void *ctx)
+ enum genbind_node_type type,
+ genbind_callback_t *cb,
+ void *ctx)
{
- int ret;
-
- if (node == NULL) {
- return -1;
- }
- if (node->l != NULL) {
- ret = genbind_node_foreach_type(node->l, type, cb, ctx);
- if (ret != 0) {
- return ret;
- }
- }
- if (node->type == type) {
- return cb(node, ctx);
- }
-
- return 0;
+ int ret;
+
+ if (node == NULL) {
+ return -1;
+ }
+ if (node->l != NULL) {
+ ret = genbind_node_foreach_type(node->l, type, cb, ctx);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+ if (node->type == type) {
+ return cb(node, ctx);
+ }
+
+ return 0;
}
static int genbind_enumerate_node(struct genbind_node *node, void *ctx)
{
- node = node;
- (*((int *)ctx))++;
- return 0;
+ node = node;
+ (*((int *)ctx))++;
+ return 0;
}
/* exported interface defined in nsgenbind-ast.h */
int
genbind_node_enumerate_type(struct genbind_node *node,
- enum genbind_node_type type)
+ enum genbind_node_type type)
{
- int count = 0;
- genbind_node_foreach_type(node,
- type,
- genbind_enumerate_node,
- &count);
- return count;
+ int count = 0;
+ genbind_node_foreach_type(node,
+ type,
+ genbind_enumerate_node,
+ &count);
+ return count;
}
/* exported interface defined in nsgenbind-ast.h */
struct genbind_node *
genbind_node_find(struct genbind_node *node,
- struct genbind_node *prev,
- genbind_callback_t *cb,
- void *ctx)
+ struct genbind_node *prev,
+ genbind_callback_t *cb,
+ void *ctx)
{
- struct genbind_node *ret;
+ struct genbind_node *ret;
- if ((node == NULL) || (node == prev)) {
- return NULL;
- }
+ if ((node == NULL) || (node == prev)) {
+ return NULL;
+ }
- if (node->l != prev) {
- ret = genbind_node_find(node->l, prev, cb, ctx);
- if (ret != NULL) {
- return ret;
- }
- }
+ if (node->l != prev) {
+ ret = genbind_node_find(node->l, prev, cb, ctx);
+ if (ret != NULL) {
+ return ret;
+ }
+ }
- if (cb(node, ctx) != 0) {
- return node;
- }
+ if (cb(node, ctx) != 0) {
+ return node;
+ }
- return NULL;
+ return NULL;
}
/* exported interface documented in nsgenbind-ast.h */
struct genbind_node *
genbind_node_find_type(struct genbind_node *node,
- struct genbind_node *prev,
- enum genbind_node_type type)
+ struct genbind_node *prev,
+ enum genbind_node_type type)
{
- return genbind_node_find(node,
- prev,
- genbind_cmp_node_type,
- (void *)type);
+ return genbind_node_find(node,
+ prev,
+ genbind_cmp_node_type,
+ (void *)type);
}
/* exported interface documented in nsgenbind-ast.h */
struct genbind_node *
genbind_node_find_type_ident(struct genbind_node *node,
- struct genbind_node *prev,
- enum genbind_node_type type,
- const char *ident)
+ struct genbind_node *prev,
+ enum genbind_node_type type,
+ const char *ident)
{
- struct genbind_node *found_node;
- struct genbind_node *ident_node;
-
- if (ident == NULL) {
- return NULL;
- }
-
- found_node = genbind_node_find_type(node, prev, type);
-
- while (found_node != NULL) {
- /* look for an ident node */
- ident_node = genbind_node_find_type(
- genbind_node_getnode(found_node),
- NULL,
- GENBIND_NODE_TYPE_IDENT);
-
- while (ident_node != NULL) {
- /* check for matching text */
- if (strcmp(ident_node->r.text, ident) == 0) {
- return found_node;
- }
-
- ident_node = genbind_node_find_type(
- genbind_node_getnode(found_node),
- ident_node,
- GENBIND_NODE_TYPE_IDENT);
- }
-
-
- /* look for next matching node */
- found_node = genbind_node_find_type(node, found_node, type);
- }
- return found_node;
+ struct genbind_node *found_node;
+ struct genbind_node *ident_node;
+
+ if (ident == NULL) {
+ return NULL;
+ }
+
+ found_node = genbind_node_find_type(node, prev, type);
+
+ while (found_node != NULL) {
+ /* look for an ident node */
+ ident_node = genbind_node_find_type(
+ genbind_node_getnode(found_node),
+ NULL,
+ GENBIND_NODE_TYPE_IDENT);
+
+ while (ident_node != NULL) {
+ /* check for matching text */
+ if (strcmp(ident_node->r.text, ident) == 0) {
+ return found_node;
+ }
+
+ ident_node = genbind_node_find_type(
+ genbind_node_getnode(found_node),
+ ident_node,
+ GENBIND_NODE_TYPE_IDENT);
+ }
+
+
+ /* look for next matching node */
+ found_node = genbind_node_find_type(node, found_node, type);
+ }
+ return found_node;
}
/* exported interface documented in nsgenbind-ast.h */
struct genbind_node *
genbind_node_find_type_type(struct genbind_node *node,
- struct genbind_node *prev,
- enum genbind_node_type type,
- const char *ident)
+ struct genbind_node *prev,
+ enum genbind_node_type type,
+ const char *ident)
{
- struct genbind_node *found_node;
- struct genbind_node *ident_node;
-
- found_node = genbind_node_find_type(node, prev, type);
-
-
- while (found_node != NULL) {
- /* look for a type node */
- ident_node = genbind_node_find_type(genbind_node_getnode(found_node),
- NULL,
- GENBIND_NODE_TYPE_TYPE);
- if (ident_node != NULL) {
- if (strcmp(ident_node->r.text, ident) == 0)
- break;
- }
-
- /* look for next matching node */
- found_node = genbind_node_find_type(node, found_node, type);
- }
- return found_node;
+ struct genbind_node *found_node;
+ struct genbind_node *ident_node;
+
+ found_node = genbind_node_find_type(node, prev, type);
+
+
+ while (found_node != NULL) {
+ /* look for a type node */
+ ident_node = genbind_node_find_type(genbind_node_getnode(found_node),
+ NULL,
+ GENBIND_NODE_TYPE_TYPE);
+ if (ident_node != NULL) {
+ if (strcmp(ident_node->r.text, ident) == 0)
+ break;
+ }
+
+ /* look for next matching node */
+ found_node = genbind_node_find_type(node, found_node, type);
+ }
+ return found_node;
}
int genbind_cmp_node_type(struct genbind_node *node, void *ctx)
{
- if (node->type == (enum genbind_node_type)ctx)
- return 1;
- return 0;
+ if (node->type == (enum genbind_node_type)ctx)
+ return 1;
+ return 0;
}
char *genbind_node_gettext(struct genbind_node *node)
{
- if (node != NULL) {
- switch(node->type) {
- case GENBIND_NODE_TYPE_WEBIDLFILE:
- case GENBIND_NODE_TYPE_STRING:
- case GENBIND_NODE_TYPE_PREAMBLE:
- case GENBIND_NODE_TYPE_PROLOGUE:
- case GENBIND_NODE_TYPE_EPILOGUE:
- case GENBIND_NODE_TYPE_IDENT:
- case GENBIND_NODE_TYPE_TYPE:
- case GENBIND_NODE_TYPE_CBLOCK:
- return node->r.text;
-
- default:
- break;
- }
- }
- return NULL;
+ if (node != NULL) {
+ switch(node->type) {
+ case GENBIND_NODE_TYPE_WEBIDL:
+ case GENBIND_NODE_TYPE_STRING:
+ case GENBIND_NODE_TYPE_PREFACE:
+ case GENBIND_NODE_TYPE_PROLOGUE:
+ case GENBIND_NODE_TYPE_EPILOGUE:
+ case GENBIND_NODE_TYPE_POSTFACE:
+ case GENBIND_NODE_TYPE_IDENT:
+ case GENBIND_NODE_TYPE_TYPE:
+ case GENBIND_NODE_TYPE_CDATA:
+ return node->r.text;
+
+ default:
+ break;
+ }
+ }
+ return NULL;
}
struct genbind_node *genbind_node_getnode(struct genbind_node *node)
{
- if (node != NULL) {
- switch(node->type) {
- case GENBIND_NODE_TYPE_HDRCOMMENT:
- case GENBIND_NODE_TYPE_BINDING:
- case GENBIND_NODE_TYPE_BINDING_PRIVATE:
- case GENBIND_NODE_TYPE_BINDING_INTERNAL:
- case GENBIND_NODE_TYPE_BINDING_PROPERTY:
- case GENBIND_NODE_TYPE_BINDING_INTERFACE:
- case GENBIND_NODE_TYPE_BINDING_INTERFACE_FLAGS:
- case GENBIND_NODE_TYPE_OPERATION:
- case GENBIND_NODE_TYPE_API:
- case GENBIND_NODE_TYPE_GETTER:
- case GENBIND_NODE_TYPE_SETTER:
- return node->r.node;
-
- default:
- break;
- }
- }
- return NULL;
+ if (node != NULL) {
+ switch(node->type) {
+ case GENBIND_NODE_TYPE_BINDING:
+ case GENBIND_NODE_TYPE_CLASS:
+ case GENBIND_NODE_TYPE_PRIVATE:
+ case GENBIND_NODE_TYPE_INTERNAL:
+ case GENBIND_NODE_TYPE_PROPERTY:
+ case GENBIND_NODE_TYPE_FLAGS:
+ case GENBIND_NODE_TYPE_METHOD:
+ case GENBIND_NODE_TYPE_PARAMETER:
+ return node->r.node;
+
+ default:
+ break;
+ }
+ }
+ return NULL;
}
int *genbind_node_getint(struct genbind_node *node)
{
- if (node != NULL) {
- switch(node->type) {
- case GENBIND_NODE_TYPE_MODIFIER:
- return &node->r.number;
-
- default:
- break;
- }
- }
- return NULL;
+ if (node != NULL) {
+ switch(node->type) {
+ case GENBIND_NODE_TYPE_METHOD_TYPE:
+ case GENBIND_NODE_TYPE_MODIFIER:
+ return &node->r.number;
+
+ default:
+ break;
+ }
+ }
+ return NULL;
}
static const char *genbind_node_type_to_str(enum genbind_node_type type)
{
- switch(type) {
- case GENBIND_NODE_TYPE_IDENT:
- return "Ident";
+ switch(type) {
+ case GENBIND_NODE_TYPE_IDENT:
+ return "Ident";
- case GENBIND_NODE_TYPE_ROOT:
- return "Root";
+ case GENBIND_NODE_TYPE_ROOT:
+ return "Root";
- case GENBIND_NODE_TYPE_WEBIDLFILE:
- return "webidlfile";
+ case GENBIND_NODE_TYPE_WEBIDL:
+ return "webidl";
- case GENBIND_NODE_TYPE_HDRCOMMENT:
- return "HdrComment";
+ case GENBIND_NODE_TYPE_STRING:
+ return "String";
- case GENBIND_NODE_TYPE_STRING:
- return "String";
+ case GENBIND_NODE_TYPE_PREFACE:
+ return "Preface";
- case GENBIND_NODE_TYPE_PREAMBLE:
- return "Preamble";
+ case GENBIND_NODE_TYPE_POSTFACE:
+ return "Postface";
- case GENBIND_NODE_TYPE_BINDING:
- return "Binding";
+ case GENBIND_NODE_TYPE_PROLOGUE:
+ return "Prologue";
- case GENBIND_NODE_TYPE_TYPE:
- return "Type";
+ case GENBIND_NODE_TYPE_EPILOGUE:
+ return "Epilogue";
- case GENBIND_NODE_TYPE_BINDING_PRIVATE:
- return "Private";
+ case GENBIND_NODE_TYPE_BINDING:
+ return "Binding";
- case GENBIND_NODE_TYPE_BINDING_INTERNAL:
- return "Internal";
+ case GENBIND_NODE_TYPE_TYPE:
+ return "Type";
- case GENBIND_NODE_TYPE_BINDING_INTERFACE:
- return "Interface";
+ case GENBIND_NODE_TYPE_PRIVATE:
+ return "Private";
- case GENBIND_NODE_TYPE_BINDING_INTERFACE_FLAGS:
- return "Flags";
+ case GENBIND_NODE_TYPE_INTERNAL:
+ return "Internal";
- case GENBIND_NODE_TYPE_BINDING_PROPERTY:
- return "Property";
+ case GENBIND_NODE_TYPE_CLASS:
+ return "Class";
- case GENBIND_NODE_TYPE_OPERATION:
- return "Operation";
+ case GENBIND_NODE_TYPE_FLAGS:
+ return "Flags";
- case GENBIND_NODE_TYPE_API:
- return "API";
+ case GENBIND_NODE_TYPE_PROPERTY:
+ return "Property";
- case GENBIND_NODE_TYPE_GETTER:
- return "Getter";
+ case GENBIND_NODE_TYPE_METHOD:
+ return "Method";
- case GENBIND_NODE_TYPE_SETTER:
- return "Setter";
+ case GENBIND_NODE_TYPE_METHOD_TYPE:
+ return "Type";
- case GENBIND_NODE_TYPE_CBLOCK:
- return "CBlock";
+ case GENBIND_NODE_TYPE_PARAMETER:
+ return "Parameter";
- default:
- return "Unknown";
- }
+ case GENBIND_NODE_TYPE_CDATA:
+ return "CBlock";
+
+ default:
+ return "Unknown";
+ }
}
-int genbind_ast_dump(struct genbind_node *node, int indent)
+/** dump ast node to file at indent level */
+static int genbind_ast_dump(FILE *dfile, struct genbind_node *node, int indent)
{
- const char *SPACES=" ";
- char *txt;
-
- while (node != NULL) {
- printf("%.*s%s", indent, SPACES, genbind_node_type_to_str(node->type));
-
- txt = genbind_node_gettext(node);
- if (txt == NULL) {
- printf("\n");
- genbind_ast_dump(genbind_node_getnode(node), indent + 2);
- } else {
- printf(": \"%.*s\"\n", 75 - indent, txt);
- }
- node = node->l;
- }
- return 0;
+ const char *SPACES=" ";
+ char *txt;
+ int *val;
+
+ while (node != NULL) {
+ fprintf(dfile, "%.*s%s", indent, SPACES,
+ genbind_node_type_to_str(node->type));
+
+ txt = genbind_node_gettext(node);
+ if (txt == NULL) {
+ val = genbind_node_getint(node);
+ if (val == NULL) {
+ fprintf(dfile, "\n");
+ genbind_ast_dump(dfile,
+ genbind_node_getnode(node),
+ indent + 2);
+ } else {
+ fprintf(dfile, ": %d\n", *val);
+ }
+ } else {
+ fprintf(dfile, ": \"%.*s\"\n", 75 - indent, txt);
+ }
+ node = node->l;
+ }
+ return 0;
}
-FILE *genbindopen(const char *filename)
+
+/* exported interface documented in nsgenbind-ast.h */
+int genbind_dump_ast(struct genbind_node *node)
{
- FILE *genfile;
- char *fullname;
- int fulllen;
- static char *prevfilepath = NULL;
-
- /* try filename raw */
- genfile = fopen(filename, "r");
- if (genfile != NULL) {
- if (options->verbose) {
- printf("Opened Genbind file %s\n", filename);
- }
- if (prevfilepath == NULL) {
- fullname = strrchr(filename, '/');
- if (fullname == NULL) {
- fulllen = strlen(filename);
- } else {
- fulllen = fullname - filename;
- }
- prevfilepath = strndup(filename,fulllen);
- }
- if (options->depfilehandle != NULL) {
- fprintf(options->depfilehandle, " \\\n\t%s",
- filename);
- }
- return genfile;
- }
-
- /* try based on previous filename */
- if (prevfilepath != NULL) {
- fulllen = strlen(prevfilepath) + strlen(filename) + 2;
- fullname = malloc(fulllen);
- snprintf(fullname, fulllen, "%s/%s", prevfilepath, filename);
- if (options->debug) {
- printf("Attempting to open Genbind file %s\n", fullname);
- }
- genfile = fopen(fullname, "r");
- if (genfile != NULL) {
- if (options->verbose) {
- printf("Opened Genbind file %s\n", fullname);
- }
- if (options->depfilehandle != NULL) {
- fprintf(options->depfilehandle, " \\\n\t%s",
- fullname);
- }
- free(fullname);
- return genfile;
- }
- free(fullname);
- }
-
- /* try on idl path */
- if (options->idlpath != NULL) {
- fulllen = strlen(options->idlpath) + strlen(filename) + 2;
- fullname = malloc(fulllen);
- snprintf(fullname, fulllen, "%s/%s", options->idlpath, filename);
- genfile = fopen(fullname, "r");
- if ((genfile != NULL) && options->verbose) {
- printf("Opend Genbind file %s\n", fullname);
- if (options->depfilehandle != NULL) {
- fprintf(options->depfilehandle, " \\\n\t%s",
- fullname);
- }
- }
-
- free(fullname);
- }
-
- return genfile;
+ FILE *dumpf;
+
+ /* only dump AST to file if required */
+ if (!options->debug) {
+ return 0;
+ }
+
+ dumpf = genb_fopen("binding-ast", "w");
+ if (dumpf == NULL) {
+ return 2;
+ }
+
+ genbind_ast_dump(dumpf, node, 0);
+
+ fclose(dumpf);
+
+ return 0;
}
-int genbind_parsefile(char *infilename, struct genbind_node **ast)
+FILE *genbindopen(const char *filename)
{
- FILE *infile;
-
- /* open input file */
- if ((infilename[0] == '-') &&
- (infilename[1] == 0)) {
- if (options->verbose) {
- printf("Using stdin for input\n");
- }
- infile = stdin;
- } else {
- infile = genbindopen(infilename);
- }
-
- if (!infile) {
- fprintf(stderr, "Error opening %s: %s\n",
- infilename,
- strerror(errno));
- return 3;
- }
-
- if (options->debug) {
- nsgenbind_debug = 1;
- nsgenbind__flex_debug = 1;
- }
-
- /* set flex to read from file */
- nsgenbind_restart(infile);
-
- /* process binding */
- return nsgenbind_parse(ast);
+ FILE *genfile;
+ char *fullname;
+ int fulllen;
+ static char *prevfilepath = NULL;
+
+ /* try filename raw */
+ genfile = fopen(filename, "r");
+ if (genfile != NULL) {
+ if (options->verbose) {
+ printf("Opened Genbind file %s\n", filename);
+ }
+ if (prevfilepath == NULL) {
+ fullname = strrchr(filename, '/');
+ if (fullname == NULL) {
+ fulllen = strlen(filename);
+ } else {
+ fulllen = fullname - filename;
+ }
+ prevfilepath = strndup(filename,fulllen);
+ }
+#if 0
+ if (options->depfilehandle != NULL) {
+ fprintf(options->depfilehandle, " \\\n\t%s",
+ filename);
+ }
+#endif
+ return genfile;
+ }
+
+ /* try based on previous filename */
+ if (prevfilepath != NULL) {
+ fulllen = strlen(prevfilepath) + strlen(filename) + 2;
+ fullname = malloc(fulllen);
+ snprintf(fullname, fulllen, "%s/%s", prevfilepath, filename);
+ if (options->debug) {
+ printf("Attempting to open Genbind file %s\n", fullname);
+ }
+ genfile = fopen(fullname, "r");
+ if (genfile != NULL) {
+ if (options->verbose) {
+ printf("Opened Genbind file %s\n", fullname);
+ }
+#if 0
+ if (options->depfilehandle != NULL) {
+ fprintf(options->depfilehandle, " \\\n\t%s",
+ fullname);
+ }
+#endif
+ free(fullname);
+ return genfile;
+ }
+ free(fullname);
+ }
+
+ /* try on idl path */
+ if (options->idlpath != NULL) {
+ fulllen = strlen(options->idlpath) + strlen(filename) + 2;
+ fullname = malloc(fulllen);
+ snprintf(fullname, fulllen, "%s/%s", options->idlpath, filename);
+ genfile = fopen(fullname, "r");
+ if ((genfile != NULL) && options->verbose) {
+ printf("Opend Genbind file %s\n", fullname);
+#if 0
+ if (options->depfilehandle != NULL) {
+ fprintf(options->depfilehandle, " \\\n\t%s",
+ fullname);
+ }
+#endif
+ }
+
+ free(fullname);
+ }
+ return genfile;
}
-#ifdef NEED_STRNDUP
+/**
+ * standard IO handle for parse trace logging.
+ */
+static FILE *genbind_parsetracef;
-char *strndup(const char *s, size_t n)
+int genbind_parsefile(char *infilename, struct genbind_node **ast)
{
- size_t len;
- char *s2;
-
- for (len = 0; len != n && s[len]; len++)
- continue;
+ FILE *infile;
+ int ret;
+
+ /* open input file */
+ infile = genbindopen(infilename);
+ if (!infile) {
+ fprintf(stderr, "Error opening %s: %s\n",
+ infilename,
+ strerror(errno));
+ return 3;
+ }
+
+ /* if debugging enabled enable parser tracing and send to file */
+ if (options->debug) {
+ nsgenbind_debug = 1;
+ nsgenbind__flex_debug = 1;
+ genbind_parsetracef = genb_fopen("binding-trace", "w");
+ } else {
+ genbind_parsetracef = NULL;
+ }
+
+ /* set flex to read from file */
+ nsgenbind_restart(infile);
+
+ /* process binding */
+ ret = nsgenbind_parse(ast);
+
+ /* close tracefile if open */
+ if (genbind_parsetracef != NULL) {
+ fclose(genbind_parsetracef);
+ }
+
+ return ret;
+}
- s2 = malloc(len + 1);
- if (!s2)
- return 0;
+int genbind_fprintf(FILE *stream, const char *format, ...)
+{
+ va_list ap;
+ int ret;
- memcpy(s2, s, len);
- s2[len] = 0;
- return s2;
-}
+ va_start(ap, format);
-#endif
+ if (genbind_parsetracef == NULL) {
+ ret = vfprintf(stream, format, ap);
+ } else {
+ ret = vfprintf(genbind_parsetracef, format, ap);
+ }
+ va_end(ap);
+ return ret;
+}