Exemplo n.º 1
0
corto_string corto_buffer_str(corto_buffer *b) {
    corto_string result = NULL;

    if (b->elementCount) {
        if (b->buf) {
            result = corto_strdup(b->buf);
        } else {
            void *next = NULL;
            corto_uint32 len = (b->elementCount - 1) * CORTO_BUFFER_ELEMENT_SIZE +
                b->current->pos + 1;

            corto_buffer_element *e = &b->firstElement;

            result = corto_alloc(len);
            corto_string ptr = result;

            do {
                memcpy(ptr, e->buf, e->pos);
                ptr += e->pos;
                next = e->next;
                if (e != &b->firstElement) {
                    corto_dealloc(e);
                }
            } while ((e = next));

            result[len - 1] = '\0';
        }
    } else {
        result = NULL;
    }

    b->elementCount = 0;

    return result;
}
Exemplo n.º 2
0
corto_iter corto_llIterAlloc(corto_ll list) {
    corto_iter result;
    corto_llIter_s *udata =  corto_alloc(sizeof(corto_llIter_s));
    result = _corto_llIter(list, udata);
    result.release = corto_llIterRelease;
    return result;
}
Exemplo n.º 3
0
/* Register a filetype */
int corto_load_register(corto_string ext, corto_loadAction handler, void* userData) {
    struct corto_fileHandler* h;

    /* Check if extension is already registered */
    corto_mutexLock(&corto_adminLock);
    if ((h = corto_lookupExt(ext))) {
        if (h->load != handler) {
            corto_error("corto_load_register: extension '%s' is already registered with another loader.", ext);
            abort();
            goto error;
        }
    } else {
        h = corto_alloc(sizeof(struct corto_fileHandler));
        h->ext = ext;
        h->load = handler;
        h->userData = userData;

        if (!fileHandlers) {
            fileHandlers = corto_ll_new();
        }

        corto_ll_append(fileHandlers, h);
    }
    corto_mutexUnlock(&corto_adminLock);

    return 0;
error:
    return -1;
}
Exemplo n.º 4
0
corto_err corto_logv(corto_err kind, unsigned int level, char* fmt, va_list arg, FILE* f) {
    char buff[CORTO_MAX_LOG + 1];
    size_t n = 0;
    corto_string alloc = NULL;
    corto_string msg = buff;
    va_list argcpy;
    va_copy(argcpy, arg); /* Make copy of arglist in
                           * case vsnprintf needs to be called twice */

    CORTO_UNUSED(level);

    if ((n = (vsnprintf(buff, CORTO_MAX_LOG, fmt, arg) + 1)) > CORTO_MAX_LOG) {
        alloc = corto_alloc(n + 2);
        vsnprintf(alloc, n, fmt, argcpy);
        msg = alloc;
    }

    n = strlen(msg);

    strcat(msg, "\n");
    n++;

    if (f == stderr) {
        fprintf(f,  "%s%s%s", RED, msg, NORMAL);
    } else {
        fprintf(f, "%s", msg);
    }

    if (alloc) {
        corto_dealloc(alloc);
    }

    return kind;
}
Exemplo n.º 5
0
corto_fileMonitor* cortotool_monitorNew(char *file, char *lib) {
    corto_fileMonitor *mon = corto_alloc(sizeof(corto_fileMonitor));
    mon->file = corto_strdup(file);
    mon->lib = lib ? corto_strdup(lib) : NULL;
    mon->mtime = 0;

    return mon;
}
Exemplo n.º 6
0
static void CORTO_NAME_BINARYOP(string,add)(void* op1, void* op2, void* result) {
    corto_uint32 len = strlen(*(corto_string*)op1) + strlen(*(corto_string*)op2);
    if (*(corto_string*)result) {
        corto_dealloc(*(corto_string*)result);
    }
    *(corto_string*)result = corto_alloc(len + 1);
    sprintf(*(corto_string*)result, "%s%s", *(corto_string*)op1, *(corto_string*)op2);
}
Exemplo n.º 7
0
/* Add an extra element to the buffer */
static void corto_buffer_grow(corto_buffer *b) {
    /* Allocate new element */
    corto_buffer_element *e = corto_alloc(sizeof(corto_buffer_element));
    b->current->next = e;
    b->current = e;
    e->pos = 0;
    e->next = NULL;
    b->elementCount ++;
}
Exemplo n.º 8
0
/* Walk objects in correct dependency order. */
corto_depresolver corto_depresolverCreate(corto_depresolver_action onDeclare, corto_depresolver_action onDefine, void* userData) {
    corto_depresolver result;

    result = corto_alloc(sizeof(struct corto_depresolver_s));

    result->items = corto_llNew();
    result->toPrint = corto_llNew();
    result->onDeclare = onDeclare;
    result->onDefine = onDefine;
    result->userData = userData;

    return result;
}
Exemplo n.º 9
0
static corto_errThreadData* corto_getThreadData(void){
    corto_errThreadData* result;
    if (!corto_errKey) {
        corto_threadTlsKey(&corto_errKey, corto_lasterrorFree);
    }
    result = corto_threadTlsGet(corto_errKey);
    if (!result) {
        result = corto_alloc(sizeof(corto_errThreadData));
        memset(result, 0, sizeof(corto_errThreadData));
        corto_threadTlsSet(corto_errKey, result);
    }
    return result;
}
Exemplo n.º 10
0
/* Create new item */
g_item g_itemNew(corto_object o, corto_depresolver data) {
    g_item result;

    result = corto_alloc(sizeof(struct g_item));
    result->o = o;
    result->declared = FALSE;
    result->defined = FALSE;
    result->declareCount = 0;
    result->defineCount = 0;
    result->onDeclared = NULL;
    result->onDefined = NULL;

    if (o == root_o) {
        result->declared = TRUE;
        result->defined = TRUE;
    }

    corto_llInsert(data->items, result);

    return result;
}
Exemplo n.º 11
0
/* Do metawalk on type */
int16_t _corto_metawalk(
    corto_walk_opt* s,
    corto_type type,
    void* userData)
{
    corto__object* o;
    int16_t result;

    /* Since we potentially overwrite some callbacks, make private copy */
    corto_walk_opt private = *s;

    ut_assert(type != NULL, "corto_metawalk called with NULL type");

    /* Instantiate dummy-object */
    o = corto_alloc(sizeof(corto__object) + type->size);
    memset(o, 0, sizeof(corto__object) + type->size);
    o->type = corto_type(type);
    o->refcount = 1;
#ifndef NDEBUG
    o->magic = CORTO_MAGIC;
#endif
    private.visitAllCases = TRUE;
Exemplo n.º 12
0
/* Add indexInfo to indextable for each primitive */
static corto_int16 corto_string_deserBuildIndexPrimitive(corto_walk_opt* s, corto_value* v, void* userData) {
    corto_string_deser_t* data;
    struct corto_string_deserIndexInfo *newInfo;
    corto_member m;

    CORTO_UNUSED(s);

    data = userData;

    /* Lookup member */
    m = v->is.member.t;

    /* Create new info-object */
    newInfo = corto_alloc(sizeof(struct corto_string_deserIndexInfo));
    newInfo->m = m;
    newInfo->type = m->type;
    newInfo->parsed = FALSE;

    /* Insert indexInfo into index */
    corto_string_deserIndexInsert(data, newInfo);

    return 0;
}
Exemplo n.º 13
0
/* Parse scope */
static corto_string corto_string_deserParseScope(corto_string str, struct corto_string_deserIndexInfo* info, corto_string_deser_t* data) {
    struct corto_string_deserIndexInfo rootInfo;
    corto_typeKind kind;
    void *ptr = data->ptr;

    if (data->allocValue) {
        ptr = data->allocValue(ptr, data);
    }

    /* Prepare privateData */
    corto_string_deser_t privateData = {
        .out = data->out,
        .scope = data->scope,
        .anonymousObjects = data->anonymousObjects,
        .type = data->type,
        .isObject = data->isObject,
        .members = {0, NULL}
    };

    /* Offset the scope-members with the current offset */
    if (info && info->m) {
        ptr = corto_getMemberPtr(data->isObject ? data->out : NULL, ptr, info->m);
    }
    privateData.ptr = ptr;

    /* Open scope of type */
    if (!info) {
        if (!data->type) {
            rootInfo.type = corto_typeof(data->out);
        } else {
            rootInfo.type = data->type;
        }
        rootInfo.m = NULL;
        rootInfo.parsed = FALSE;
        info = &rootInfo;
    }

    /* Check if type is any, composite or collection */
    kind = info->type->kind;

    if ((kind != CORTO_COMPOSITE) && (kind != CORTO_COLLECTION) && (kind != CORTO_ANY)) {
        corto_seterr("'{' unexpected for type '%s'",
            corto_fullpath(NULL, info->type));
        goto error;
    }

    /* Build index for type */
    if (info->type->kind == CORTO_COMPOSITE) {
        if (corto_interface(info->type)->kind == CORTO_UNION) {
            /* Parse discriminator */
            struct corto_string_deserIndexInfo dInfo;
            dInfo.type = (corto_type)corto_int32_o;
            dInfo.parsed = FALSE;
            dInfo.m = NULL;
            str = corto_string_deserParse(str + 1, &dInfo, &privateData);
            if (!str) {
                goto error;
            }

            /* Find corresponding union case */
            corto_int32 d = *(corto_int32*)ptr;
            corto_member m = safe_corto_union_findCase(info->type, d);
            if (!m) {
                corto_seterr("discriminator '%d' invalid for union '%s'",
                    d, corto_fullpath(NULL, info->type));
                goto error;
            }

            /* Build index for one member */
            struct corto_string_deserIndexInfo *caseInfo =
                corto_alloc(sizeof(struct corto_string_deserIndexInfo));
            caseInfo->type = m->type;
            caseInfo->parsed = FALSE;
            caseInfo->m = m;
            corto_string_deserIndexInsert(&privateData, caseInfo);
        } else {
            corto_walk_opt s = corto_string_deserBuildIndex();
            s.members = data->members;
            if (s.members.length) {
                s.access = 0;
            }
            if (corto_metawalk(&s, info->type, &privateData)) {
                goto error;
            }
        }

        /* Create iterator for index */
        if (privateData.index) {
            privateData.currentIter = _corto_ll_iter(privateData.index, &privateData.iterData);
        }
    /* If type is a collection, build index with one node for element */
    } else if (info->type->kind == CORTO_COLLECTION) {
        struct corto_string_deserIndexInfo *elementNode;
        elementNode = corto_alloc(sizeof(struct corto_string_deserIndexInfo));
        elementNode->m = NULL;
        elementNode->parsed = FALSE;
        elementNode->type = corto_collection(info->type)->elementType;
        corto_string_deserIndexInsert(&privateData, elementNode);

        /* Create iterator for index */
        privateData.currentIter = _corto_ll_iter(privateData.index, &privateData.iterData);
        privateData.allocValue = corto_string_deserAllocElem;
        privateData.allocUdata = info->type;

        if (ptr) {
            switch(corto_collection(info->type)->kind) {
            case CORTO_ARRAY:
            case CORTO_SEQUENCE:
                break;
            case CORTO_LIST:
                if (!*(corto_ll*)ptr) {
                    *(corto_ll*)ptr = corto_ll_new();
                } else {
                    corto_ll_clear(*(corto_ll*)ptr);
                }
                privateData.ptr = ptr;
                break;
            default:
                break;
            }
        }
    } else if (info->type->kind == CORTO_ANY) {
          struct corto_string_deserIndexInfo *anyNode;
          anyNode = corto_alloc(sizeof(struct corto_string_deserIndexInfo));
          anyNode->m = NULL;
          anyNode->parsed = FALSE;
          anyNode->type = corto_type(corto_type_o);
          corto_string_deserIndexInsert(&privateData, anyNode);
          privateData.currentIter = _corto_ll_iter(privateData.index, &privateData.iterData);
          privateData.allocValue = corto_string_deserAllocAny;
          privateData.allocUdata = anyNode;
    }

    /* Parse scope */
    if (!(str = corto_string_deserParse(str+1, info, &privateData))) {
        goto error;
    }

    corto_string_deserFreeIndex(&privateData);

    data->anonymousObjects = privateData.anonymousObjects;

    return str;
error:
    return NULL;
}

/* Get pointer to current destination value */
corto_int16 corto_string_getDestinationPtr(
    struct corto_string_deserIndexInfo* info,
    corto_string_deser_t* data,
    void **ptr_out)
{
    void *result = data->ptr;

    *ptr_out = NULL;

    if (!info) {
        corto_seterr("excess elements in string");
        goto error;
    }

    if (data->allocValue) {
        result = data->allocValue(result, data);
    }

    if (info->m) {
        result = corto_getMemberPtr(data->isObject ? data->out : NULL, data->ptr, info->m);
    }

    *ptr_out = result;

    return 0;
error:
    return -1;
}
Exemplo n.º 14
0
 * web_SockJsServer_Connection.c
 *
 * Only code written between the begin and end tags will be preserved
 * when the file is regenerated.
 */

#include "web.h"

/* $header() */
#include "mongoose.h"
/* $end */

corto_void _web_SockJsServer_Connection_send(web_SockJsServer_Connection this, corto_string msg) {
/* $begin(::corto::web::SockJsServer::Connection::send) */
	int escapedLength;
	corto_string sockJsMsg;

	/* Escape & pack message in SockJS header */
	escapedLength = stresc(NULL, 0, msg);
	sockJsMsg = corto_alloc(escapedLength + strlen("a[\"\"]") + 1);
	sprintf(sockJsMsg, "a[\"%*s\"]", escapedLength, " ");
	stresc(sockJsMsg + 3, escapedLength, msg);

	if (this->conn) {
		mg_websocket_printf((struct mg_connection *)this->conn, WEBSOCKET_OPCODE_TEXT, sockJsMsg);
	}

	corto_dealloc(sockJsMsg);
/* $end */
}
Exemplo n.º 15
0
/* Find existing parts in the code that must not be overwritten. */
static corto_ll cdiff_parseLegacy(char *code) {
    char *ptr = NULL;
    corto_ll result = corto_ll_new();

    ptr = code;

    while((ptr = strchr(ptr, '$'))) {
        cdiff_elemKind kind = CDIFF_TEXT;

        if (!memcmp(ptr, "$begin", 6)) {
            ptr += 6;
            kind = CDIFF_FUNCTION_LEGACY;
        } else if (!memcmp(ptr, "$header", 7)) {
            ptr += 7;
        } else {
            ptr ++;
            continue;
        }

        /* Find begin of identifier */
        if (*ptr == '(') {
            char *endptr;

            /* Find end of identifier */
            endptr = strstr(ptr, ") */");
            if (endptr) {
                corto_id identifier;

                /* Copy identifier string */
                *endptr = '\0';
                endptr += 3;

                if (strlen(ptr) >= sizeof(corto_id)) {
                    corto_seterr(
                        "%s: identifier of code-snippet exceeds %d characters", sizeof(corto_id));
                    goto error;
                }

                strcpy(identifier, ptr + 1);
                ptr = endptr + 1;

                /* Find $end */
                endptr = strstr(ptr, "$end");
                endptr -= 3; /* include comment begin token */

                if (endptr) {
                    cdiff_elem* el;
                    corto_string src;

                    if (kind != CDIFF_TEXT) {
                        endptr[0] = '}';
                        endptr[1] = '\n';
                        endptr[2] = '\0';
                        endptr += 3;
                    } else {
                        endptr[0] = '\n';
                        endptr[1] = '\0';
                        endptr += 2;
                    }
                    src = corto_strdup(ptr);

                    if(strstr(src, "$begin")) {
                        corto_seterr("code-snippet '%s' contains nested $begin (did you forget an $end?)",
                            identifier);
                        corto_dealloc(src);
                        goto error;
                    }

                    el = corto_alloc(sizeof(cdiff_elem));
                    el->kind = kind;
                    el->id = corto_strdup(identifier);
                    el->header = NULL;
                    el->body = src;
                    corto_ll_append(result, el);

                    ptr = endptr + 1;

                } else {
                    corto_warning("generator: missing $end after $begin(%s)", identifier);
                }
            } else {
                corto_warning("generator: missing ')' after $begin/$header");
            }
        } else {
            corto_warning("generator: missing '(' after $begin/$header");
        }
    }

    return result;
error:
    if (result) {
        corto_ll_free(result);
    }

    printf("error!\n");
    return NULL;
}
Exemplo n.º 16
0
/* Parse value */
static corto_int16 corto_string_deserParseValue(
    corto_string value,
    struct corto_string_deserIndexInfo* info,
    corto_string_deser_t* data)
{
    void *offset;
    if (corto_string_getDestinationPtr(info, data, &offset)) {
        corto_seterr("%s: %s", value, corto_lasterr());
        goto error;
    }

    /* No more elements where available in the index, meaning an excess element */
    if (!info) {
        corto_seterr("excess elements in scope @ '%s'", value);
        goto error;
    }

    /* Can typically occur when mixing short with default notation. */
    if (info->parsed) {
        corto_seterr("member '%s' is already parsed", corto_idof(info->m));
        goto error;
    }

    /* Only parse references and primitives */
    if (info->type->reference) {
        corto_object o = NULL;
        corto_uint32 index = 0;

        /* Resolve object */
        if (corto_string_deserParseAnonymousId(value, &index)) {
            if (!index) {
                if (data->isObject) {
                    o = data->out;
                    corto_claim(o);
                } else {
                    corto_seterr("cannot refer to self (<0>), not deserializing an object");
                    goto error;
                }
            } else if (data->anonymousObjects && (index <= corto_ll_size(data->anonymousObjects))) {
                o = corto_ll_get(data->anonymousObjects, index - 1);
                corto_claim(o);
            } else {
                corto_seterr("undefined anonymous identifier '%s'", value);
                goto error;
            }
        } else {
            o = corto_resolve(data->scope, value);
        }

        if (o || !strcmp(value, "null")) {
            if (offset) corto_ptr_setref(offset, o);
            if (o) corto_release(o);
        } else {
            corto_seterr("unresolved reference to '%s' for member '%s'", value,
                corto_fullpath(NULL, info->m));
            goto error;
        }
    } else

    /* Convert string to primitive value */
    if (offset && (info->type->kind == CORTO_PRIMITIVE)) {
        if (corto_primitive(info->type)->kind != CORTO_TEXT) {
            if (corto_ptr_cast(corto_primitive(corto_string_o), &value, corto_primitive(info->type), offset)) {
                goto error;
            }
        } else {
            corto_uint32 length;
            corto_string deserialized;

            if (strcmp(value, "null")) {
                length = strlen(value);
                deserialized = corto_alloc(length+1);
                memcpy(deserialized, value, length);
                deserialized[length] = '\0';
            } else {
                deserialized = NULL;
            }

            corto_ptr_setstr(offset, deserialized);
        }
    }

    /* Members are only parsed once */
    if (info->m) {
        info->parsed = TRUE;
    }

    return 0;
error:
    return -1;
}
Exemplo n.º 17
0
static int html_walkDocChilds(corto_object o, void *userData) {
    htmlData_t *data = userData;
    corto_string description = doc_getDescriptionFromDoc(o, data);
    corto_string text = doc_getTextFromDoc(o, data);
    corto_string niceName = doc_getNiceNameFromDoc(o, data);
    corto_object *docs = corto_alloc(sizeof(corto_object) * corto_scopeSize(o));
    corto_id index;
    corto_object stack[CORTO_MAX_SCOPE_DEPTH];
    corto_object ptr = o;
    corto_int32 sp = data->level;
    corto_id link;
    corto_bool noIndex = FALSE;
    corto_id upper;
    strcpy(upper, niceName);
    corto_strupper(upper);

    if (niceName[0] == '#') {
        noIndex = TRUE;
        niceName ++;
    }

    corto_string parentId = corto_idof(corto_parentof(o));
    if (parentId[0] == '#') parentId++;
    strcpy(link, parentId);
    strcat(link, "_");
    if (corto_idof(o)[0] == '#') {
        strcat(link, corto_idof(o) + 1);
    } else {
        strcat(link, corto_idof(o));
    }

    /* If level is 0, parse heading as title */
    if (!data->level) {
        data->title = niceName;
    } else {
        /* Add index number to header */
        index[0] = '\0';

        if ((sp > 1) && !noIndex) {
            while (--sp) {
                stack[sp - 1] = ptr;
                ptr = corto_parentof(ptr);
            }
            for (; sp < data->level - 1; sp ++) {
                char num[15]; sprintf(num, "%d", doc_getIndexFromDoc(stack[sp], data));
                strcat(index, num);
                strcat(index, ".");
            }
            if (data->level > 2) {
                index[strlen(index) - 1] = '\0';
            }
            strcat(index, " ");
        }

        if (data->level == 1) {
            corto_buffer_append(&data->content, "<a name=\"%s\"></a>\n<p class=\"section\">%s</p>\n",
                link,
                niceName);
        } else {
            corto_buffer_append(&data->content,
                "<a name=\"%s\"></a>\n<h%d>%s%s</h%d>\n",
                link,
                data->level,
                index,
                niceName,
                data->level);
        }

        if (data->level < 3) {
            corto_buffer_append(&data->index,
              "<li class=\"index-h%d\" onclick=\"window.location='#%s'\">%s</li>\n",
              data->level,
              link,
              data->level == 1 ? upper : niceName);
        }

        corto_buffer_append(&data->content, "<div class=\"indent\">\n");

        if (description && strlen(description)) {
            if (data->level < 3) {
                corto_buffer_append(&data->content, "<p class=\"description\">%s</p>\n", description);
            } else {
                corto_buffer_append(&data->content, "<p>%s</p>\n", description);
            }
        }

        corto_string parsedText = doc_parse(text);
        corto_buffer_append(&data->content, "%s\n", parsedText);
        corto_dealloc(parsedText);
    }

    /* Collect documents in order */
    corto_objectseq seq = corto_scopeClaim(o);
    corto_objectseqForeach(seq, doc) {
        docs[doc_getIndexFromDoc(doc, data) - 1] = doc;
    }
    corto_scopeRelease(seq);

    /* Walk documents in order */
    data->level ++;

    int i; for (i = 0; i < corto_scopeSize(o); i ++) {
        if (!html_walkDocChilds(docs[i], userData)) {
            goto error;
        }
    }
    data->level --;

    corto_buffer_append(&data->content, "</div>\n");

    corto_dealloc(docs);

    return 1;
error:
    return 0;
}
Exemplo n.º 18
0
/* strdup is not a standard C function, so provide own implementation. */
char* corto_strdup(const char* str) {
    char *result = corto_alloc(strlen(str) + 1);
    strcpy(result, str);
    return result;
}
Exemplo n.º 19
0
/* $CORTO_GENERATED
 *
 * web_DDPServer_Session.c
 *
 * Only code written between the begin and end tags will be preserved
 * when the file is regenerated.
 */

#include "web.h"

/* $header() */
corto_void web_DDPServer_Session_nosub(web_DDPServer_Session this, corto_string id) {
    int msgLength = snprintf(NULL, 0, "{\"msg\":\"nosub\",\"id\":\"%s\"}", id);
    corto_string msg = corto_alloc(msgLength + 1);
    sprintf(msg, "{\"msg\":\"nosub\",\"id\":\"%s\"}", id);
    web_SockJsServer_Connection_send(this->conn, msg);
    corto_dealloc(msg);
}
/* $end */

corto_void _web_DDPServer_Session_connected(web_DDPServer_Session this) {
/* $begin(::corto::web::DDPServer::Session::connected) */
    int msgLength = snprintf(NULL, 0, "{\"msg\":\"connected\",\"session\":\"%s\"}", corto_nameof(this));
    corto_string msg = corto_alloc(msgLength + 1);
    sprintf(msg, "{\"msg\":\"connected\",\"session\":\"%s\"}", corto_nameof(this));
    web_SockJsServer_Connection_send(this->conn, msg);
    corto_dealloc(msg);
/* $end */
}

corto_int16 _web_DDPServer_Session_construct(web_DDPServer_Session this) {
Exemplo n.º 20
0
/* Append a format string to a buffer */
static corto_bool corto_buffer_appendIntern(
    corto_buffer *b,
    corto_string str,
    void *data,
    corto_uint32 ___ (*copy)(char *dst, char *str, corto_int32 len, void *data))
{
    corto_bool result = TRUE;

    if (!str) {
        return result;
    }

    corto_buffer_init(b);

    corto_int32 spaceLeftInElement = corto_buffer_spaceLeftInCurrentElement(b);
    corto_int32 spaceLeft = corto_buffer_spaceLeft(b);

    /* Compute the memory required to add the string to the buffer */
    corto_int32 memRequired = copy(
        corto_buffer_ptr(b),
        str,
        (b->max && (spaceLeft < spaceLeftInElement)) ? spaceLeft : spaceLeftInElement + 1,
        data);

    if (b->max && (spaceLeft < memRequired)) {
        result = FALSE;
    }

    /* If the string required more memory than was available in the element,
     * grow the buffer */
    else if (memRequired >= spaceLeftInElement) {
        /* If writing to a user-provided buffer, the max is reached and append
         * should return false. Otherwise, the buffer needs to grow with extra
         * elements. */
        b->current->pos += spaceLeftInElement;
        if (!b->buf) {
            /* If the extra required memory doesn't exceed the elementsize, grow
             * a new element, vsnprintf into the element and then memmove to
             * truncate the part that was already added to the previous
             * element */
            if (memRequired < CORTO_BUFFER_ELEMENT_SIZE) {
                corto_buffer_grow(b);
                corto_int32 len = 0;

                if (b->max && (spaceLeft < CORTO_BUFFER_ELEMENT_SIZE)) {
                    len = spaceLeft;
                    result = FALSE;
                } else {
                    len = memRequired - spaceLeftInElement;
                }

                copy(corto_buffer_ptr(b), str, CORTO_BUFFER_ELEMENT_SIZE, data);
                memmove(
                    corto_buffer_ptr(b),
                    corto_buffer_ptr(b) + spaceLeftInElement,
                    len);
                b->current->pos = len;

            /* If the extra memory required exceeds the elementSize, allocate a
             * temporary string that will hold the full value, then distribute
             * the results over the new elements */
            } else {
                corto_string dst = corto_alloc(memRequired + 1);
                char *ptr = dst + spaceLeftInElement;
                corto_int32 memLeft = memRequired - spaceLeftInElement;

                /* Copy entire string to heap memory */
                copy(dst, str, memRequired + 1, data);

                /* Copy string to elements */
                while (memLeft > 0) {
                    corto_buffer_grow(b);
                    if (memLeft > CORTO_BUFFER_ELEMENT_SIZE) {
                        corto_buffer_copy(b, ptr, CORTO_BUFFER_ELEMENT_SIZE);
                        ptr += CORTO_BUFFER_ELEMENT_SIZE;
                        memLeft -= CORTO_BUFFER_ELEMENT_SIZE;
                    } else {
                        corto_buffer_copy(b, ptr, memLeft);
                        memLeft = 0;
                    }
                }
                corto_dealloc(dst);
            }
        } else {
            result = FALSE;
        }
    } else {
        b->current->pos += memRequired;
    }

    return result;
}