corto_int16 json_deserReference(void* p, corto_type t, JSON_Value* v) { switch(json_value_get_type(v)) { case JSONString: { const char* reference = json_value_get_string(v); corto_object o = corto_resolve(NULL, (corto_string)reference); if (!o) { corto_error("unresolved reference \"%s\"", reference); goto error; } if (!corto_instanceof(t, o)) { corto_error("%s is not an instance of %s", reference, corto_idof(t)); } corto_setref(p, o); corto_release(o); break; } case JSONObject: { JSON_Object* obj = json_value_get_object(v); JSON_Value* type = json_object_get_value(obj, "type"); if (json_value_get_type(type) != JSONString) { corto_seterr("type parameter of anonymous object must be a string"); goto error; } corto_type cortoType = corto_resolve(NULL, (char*)json_value_get_string(type)); if (!cortoType) { corto_seterr("type '%s' not found for anonymous object", json_value_get_string(type)); goto error; } corto_object cortoObj = *(corto_object*)p; if (!cortoObj || (corto_typeof(cortoObj) != cortoType)) { cortoObj = corto_create(cortoType); corto_setref(p, cortoObj); corto_release(cortoObj); } corto_release(cortoType); JSON_Value* value = json_object_get_value(obj, "value"); if (json_deserType(cortoObj, cortoType, value)) { goto error; } break; } case JSONNull: corto_setref(p, NULL); break; default: corto_seterr("expected string, null or object (reference), got %s", json_valueTypeToString(v)); break; } return 0; error: return -1; }
static corto_string doc_parse(corto_string input) { corto_string result = NULL; corto_function f = corto_function(corto_resolve(NULL, "md::parse")); if (corto_checkState(f, CORTO_DEFINED)) { corto_call(f, &result, input); } return result; }
corto_int16 corto_genMain(g_generator g) { htmlData_t data = { g, "doc", NULL, CORTO_BUFFER_INIT, CORTO_BUFFER_INIT, corto_resolve(NULL, "corto/md/Doc"), 0 }; if (corto_mkdir(data.output)) { goto error; } if (html_copyFiles(&data)) { goto error; } if (!g_getCurrent(g)) { corto_object doc = corto_resolve(NULL, "doc"); if (doc) { corto_id file; corto_string include; corto_scopeWalk(doc, html_walkDocChilds, &data); if ((include = g_getAttribute(data.g, "include"))) { char *ext; sprintf(file, "doc/%s", include); /* Quick & dirty way to replace extension .md with .html */ ext = strchr(file, '.'); if (ext) { strcpy(ext, ".html"); } else { strcat(file, ".html"); } } else { sprintf(file, "doc/doc.html"); } corto_id template;
corto_object md_resolve(int level, corto_string name, corto_object *parent, md_parseData* data) { corto_assert(level >= 1 && level <= 6, "Level must be between 1 and 6"); corto_object o = NULL, current = NULL; corto_object previous = NULL; if (level == 1) { previous = data->destination; } else { corto_uint32 i = level - 1; while (i && !(previous = md_Doc(data->headers[i]))) { i--; } previous = data->headers[i]; } if (previous == NULL) { goto notFound; } if (corto_instanceof(md_Doc_o, previous)) { current = md_Doc(previous)->o; } if (parent) { *parent = previous; } if (current || (level == 1)) { o = corto_resolve(current, name); if (o == NULL) { goto notFound; } if (!md_isAncestor(current, o)) { o = NULL; } } /* Clean up the lower levels of the doc hierarchy */ int i = 6; do { data->headers[i] = NULL; } while (i-- > level); return o; notFound: return NULL; }
/* Deserialize string in object */ corto_string corto_string_deser(corto_string str, corto_string_deser_t* data) { corto_char *ptr; corto_bool createdNew = FALSE; { corto_id buffer; corto_char *bptr, ch; /* Parse typename that potentially precedes string */ bptr = buffer; ptr = str; while((ch = *ptr) && (ch != '{')) { if (!((ch == ' ') || (ch == '\n') || (ch == '\t'))) { *bptr = ch; bptr++; } ptr++; } *bptr = '\0'; /* If no type is found, reset ptr */ if ((ch != '{') || (ptr == str)) { ptr = str; } else { corto_object type; /* If no out is provided create an object of the specified type */ if ((bptr != buffer)) { type = corto_resolve(NULL, buffer); if (type) { if (data->type && (type != data->type)) { corto_seterr( "type of object ('%s') does not match string ('%s')", corto_fullpath(NULL, data->type), corto_fullpath(NULL, type)); corto_release(type); goto error; } if (corto_instanceof(corto_type(corto_type_o), type)) { if (!data->out) { data->out = corto_declare(type); createdNew = TRUE; } data->type = type; } else { corto_seterr("'%s' is not a type", buffer); corto_release(type); goto error; } corto_release(type); } else { corto_seterr("unknown type '%s'", buffer); goto error; } } else { type = data->type; } if (type && (corto_type(type)->kind == CORTO_PRIMITIVE)) { ptr++; } } } data->current = 0; data->index = NULL; data->ptr = data->out; data->anonymousObjects = NULL; data->allocValue = NULL; data->allocUdata = NULL; if (data->out && data->isObject) { if (!data->type) { data->type = corto_typeof(data->out); } else if (!corto_instanceofType(corto_typeof(data->out), data->type)) { corto_seterr("object '%s' of type '%s' is not an instance of type '%s'", corto_fullpath(NULL, data->out), corto_fullpath(NULL, corto_typeof(data->out)), corto_fullpath(NULL, data->type)); goto error; } } if (!data->type) { corto_seterr("no type provided for '%s'", str); goto error; } if (data->type->kind == CORTO_PRIMITIVE) { ptr = corto_string_deserParse(ptr, NULL, data); } else { ptr = corto_string_deserParseScope(ptr, NULL, data); if (ptr) { ptr ++; } } if (!ptr) { if (!corto_lasterr()) { corto_seterr("failed to deserialize '%s'", str); } else { corto_seterr("failed to deserialize '%s': %s", str, corto_lasterr()); } goto error; } if (data->anonymousObjects) { corto_ll_free(data->anonymousObjects); } return ptr; error: if (data->out) { if (createdNew) { corto_release(data->out); } data->out = NULL; } return NULL; }
static corto_string corto_string_parseAnonymous( corto_string str, corto_string value, struct corto_string_deserIndexInfo *info, corto_string_deser_t *data) { corto_object o = NULL; char *ptr = str; char *valuePtr = value; corto_uint32 index = 0; void *offset; if (corto_string_getDestinationPtr(info, data, &offset)) { corto_seterr("%s: %s", str, corto_lasterr()); goto error; } /* Check if this is a 'named' anonymous object in which case it is * prefixed with <[id]> */ if ((valuePtr = corto_string_deserParseAnonymousId(valuePtr, &index))) { if (data->anonymousObjects && (index <= corto_ll_size(data->anonymousObjects))) { if (!*valuePtr) { o = corto_ll_get(data->anonymousObjects, index - 1); corto_claim(o); } else { /* If the <n> is followed up with more data, a new anonymous * object is being created while one existed already with the * specified number */ corto_seterr("identifier <%d> is already defined (%s)", index, value); goto error; } } } else { valuePtr = value; } /* If no object has been referenced, create an anonymous object */ if (!o && *valuePtr) { corto_object type = corto_resolve(NULL, valuePtr); if (!type) { corto_seterr("unresolved type '%s'", valuePtr); goto error; } if (offset) { o = *(corto_object*)offset; if (!o || (type != corto_typeof(o))) { if (!corto_instanceof(corto_type_o, type)) { corto_seterr("'%s' is not a type", corto_fullpath(NULL, type)); goto error; } o = corto_declare(type); if (!o) { corto_seterr("failed to declare %s: %s", value, corto_lasterr()); goto error; } } else { corto_claim(o); } } corto_string_deser_t privateData = { .out = data->out, // Preserve original out to determine ownership .ptr = o, .type = type, .anonymousObjects = data->anonymousObjects, .scope = data->scope, .isObject = data->isObject }; if (corto_type(type)->kind == CORTO_PRIMITIVE) { ptr ++; if (!(ptr = corto_string_deserParse(ptr, NULL, &privateData))) { goto error; } } else { if (!(ptr = corto_string_deserParseScope(ptr, NULL, &privateData))) { goto error; } } if (o) { if (corto_define(o)) { goto error; } data->anonymousObjects = privateData.anonymousObjects; if (!data->anonymousObjects) { data->anonymousObjects = corto_ll_new(); } corto_ll_append(data->anonymousObjects, o); } } if (offset) corto_ptr_setref(offset, o); if (o) corto_release(o); return ptr; error: if (o) corto_release(o); return NULL; }
/* 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; }
#include <test.h> corto_void _test_Packages_tc_class( test_Packages this) { /* $begin(test/Packages/tc_class) */ char text[] = "# test::Package0\n" "## Class0\n" "Description of class\n" ; md_parseToCorto(test_docs_o, text); corto_object h1 = corto_resolve(test_docs_o, "test_Package0"); test_assert(h1 != NULL); test_assert(corto_instanceof(md_Doc_o, h1)); test_assert(md_Doc(h1)->o != NULL); test_assert(!strcmp(corto_idof(md_Doc(h1)->o), "Package0")); test_assert(corto_parentof(md_Doc(h1)->o) == test_o); test_assert(md_Doc(h1)->text == NULL); test_assert(md_Doc(h1)->level == 1); corto_release(h1); corto_object h2 = corto_resolve(test_docs_o, "test_Package0::Class0"); test_assert(h2 != NULL); test_assert(corto_instanceof(md_Doc_o, h2)); test_assert(md_Doc(h2)->o != NULL); test_assert(!strcmp(corto_idof(md_Doc(h2)->o), "Class0")); test_assert(corto_parentof(md_Doc(h2)->o) == md_Doc(h1)->o);
static void mqtt_onMessage( struct mosquitto *client, void *data, const struct mosquitto_message *msg) { corto_id nameBuffer; char *name = nameBuffer; corto_object o = NULL; mqtt_Connector this = data; corto_bool isDelete = FALSE; /* If the payload has been serialized as a corto string, the typename is * potentially prefixed to the value */ char *valueStr = strchr(msg->payload, '{'); /* mqtt is the owner of this thread. This ensures that all subsequent create * update / delete actions are performed with the right owner. Ownership * ensures to not trigger on own updates, and to only forward data from * other connectors (or the application). */ corto_object prevOwner = corto_setOwner(this); /* Remove topic from name, so that name is relative to mount point. */ strcpy(name, msg->topic); if (this->topic) { name += strlen(this->topic) + 1; } char *lastElem = strrchr(name, '/'); if (lastElem && !strcmp(lastElem, "/_d")) { *lastElem = '\0'; isDelete = TRUE; } corto_debug("mqtt: %s: received '%s'", msg->topic, msg->payload); /* If object doesn't yet exist in the store, create it */ if (!(o = corto_lookup(corto_mount(this)->mount, name)) && !isDelete) { corto_id buffer; corto_debug("mqtt: creating new object for '%s'", name); /* If the mount has been configured with a fixed type, use that type to * create a new object. Otherwise, look for type in payload. */ if (corto_observer(this)->type) { strcpy(buffer, corto_observer(this)->type); } else { char *typeStr = strchr(msg->payload, '{'); memcpy(buffer, msg->payload, typeStr - (char*)msg->payload); buffer[typeStr - (char*)msg->payload] = '\0'; } /* Resolve type. If type wasn't yet loaded in corto, corto_resolve will * do a lookup on the package repository. If it doesn't exist there * either throw an error. Currently, the MQTT connector does not align * types. */ corto_type type = corto_resolve(NULL, buffer); if (!type) { corto_error("mqtt: type '%s' not found", buffer); goto error; } corto_debug("mqtt: creating '%s' with type '%s'", name, buffer); /* Create a new object under the mountpoint. The name is derived from * the MQTT topic name. */ o = corto_declareChild(corto_mount(this)->mount, name, type); if (!o) { corto_error("mqtt: failed to create object '%s'", name); goto error; } } else { corto_debug("mqtt: found '%s' for '%s'", corto_fullpath(NULL, o), name); } /* Only continue updating object when it is owned by mqtt */ if (o && corto_owned(o)) { if (isDelete) { if (corto_delete(o)) { corto_error("mqtt: failed to delete '%s': %s", name, corto_lasterr()); } corto_release(o); } else { /* Start updating object (takes a writelock) */ if (!corto_updateBegin(o)) { /* Serialize value from JSON string */ if (corto_fromcontent(o, "text/json", valueStr)) { corto_error("mqtt: failed to deserialize for %s: %s (%s)\n", name, corto_lasterr(), msg->payload); /* If deserialization fails, cancel the update. No notification * will be sent. */ corto_updateCancel(o); goto error; } /* Successful update. Send notification and unlock object */ if (corto_updateEnd(o)) { corto_error("mqtt: failed to update '%s': %s", name, corto_lasterr()); goto error; } } else { /* For some reason, couldn't start updating object */ corto_error("mqtt: failed to start updating '%s': %s", name, corto_lasterr()); goto error; } } } else if (o) { corto_debug("mqtt: '%s' not owned by me (%s, defined = %d), ignoring", corto_fullpath(NULL, o), corto_ownerof(o) ? corto_fullpath(NULL, o) : "local", corto_checkState(o, CORTO_DEFINED)); } error: /* Restore previous owner */ corto_setOwner(prevOwner); }