/** * [Map] put: [Element] at: [Key] * * Puts a key-value pair in a map. * * Usage: * * map put: 'hello' at: 'world'. * * In other languages: * Dutch: [Lijst] zet: [Object] bij: [Object] * Zet het gespecificeerde object element bij de plek die bekend staat als * het andere object. Net als bij een reeks, alleen in dit geval is het tweede * Object de sleutel waarmee het eerste object weer uit de lijst gevist kan * worden. */ ctr_object* ctr_map_put(ctr_object* myself, ctr_argument* argumentList) { char* key; long keyLen; ctr_object* putKey; ctr_object* putValue = argumentList->object; ctr_argument* nextArgument = argumentList->next; ctr_argument* emptyArgumentList = ctr_heap_allocate(sizeof(ctr_argument)); emptyArgumentList->next = NULL; emptyArgumentList->object = NULL; putKey = ctr_send_message(nextArgument->object, CTR_DICT_TOSTRING, strlen(CTR_DICT_TOSTRING), emptyArgumentList); /* If developer returns something other than string (ouch, toString), then cast anyway */ if (putKey->info.type != CTR_OBJECT_TYPE_OTSTRING) { putKey = ctr_internal_cast2string(putKey); } key = ctr_heap_allocate( putKey->value.svalue->vlen * sizeof( char ) ); keyLen = putKey->value.svalue->vlen; memcpy(key, putKey->value.svalue->value, keyLen); ctr_internal_object_delete_property(myself, ctr_build_string(key, keyLen), 0); ctr_internal_object_add_property(myself, ctr_build_string(key, keyLen), putValue, 0); ctr_heap_free( emptyArgumentList ); ctr_heap_free( key ); return myself; }
/** * StringFromLength * * Returns a portion of a string defined by from * and length values. * This message is UTF-8 unicode aware. * * Usage: * 'hello' from: 2 length: 3. #llo */ ctr_object* ctr_string_from_length(ctr_object* myself, ctr_argument* argumentList) { ctr_object* fromPos = ctr_internal_cast2number(argumentList->object); ctr_object* length = ctr_internal_cast2number(argumentList->next->object); long len = myself->value.svalue->vlen; long a = (fromPos->value.nvalue); long b = (length->value.nvalue); long ua, ub; char* dest; ctr_object* newString; if (b == 0) return ctr_build_string("",0); if (b < 0) { a = a + b; b = abs(b); } if (a < 0) a = 0; if (a > len) a = len; if ((a + b)>len) b = len - a; if ((a + b)<0) b = b - a; ua = getBytesUtf8(myself->value.svalue->value, 0, a); ub = getBytesUtf8(myself->value.svalue->value, ua, b); dest = malloc(ub * sizeof(char)); memcpy(dest, (myself->value.svalue->value) + ua, ub); newString = ctr_build_string(dest,ub); return newString; }
/** * CTRWalkerAssignment * * Processes an assignment operation. */ ctr_object* ctr_cwlk_assignment(ctr_tnode* node) { char wasReturn = 0; ctr_tlistitem* assignmentItems = node->nodes; ctr_tnode* assignee = assignmentItems->node; ctr_tlistitem* valueListItem = assignmentItems->next; ctr_tnode* value = valueListItem->node; ctr_object* x; ctr_object* result; if (ctr_flag_sandbox && ++ctr_sandbox_steps>CTR_MAX_STEPS_LIMIT) exit(1); if (CtrStdFlow == NULL) { ctr_callstack[ctr_callstack_index++] = assignee; } x = ctr_cwlk_expr(value, &wasReturn); if (assignee->modifier == 1) { result = ctr_assign_value_to_my(ctr_build_string(assignee->value, assignee->vlen), x); } else if (assignee->modifier == 2) { result = ctr_assign_value_to_local(ctr_build_string(assignee->value, assignee->vlen), x); } else { result = ctr_assign_value(ctr_build_string(assignee->value, assignee->vlen), x); } if (CtrStdFlow == NULL) { ctr_callstack_index--; } return result; }
/** * [File] read * * Reads contents of a file. */ ctr_object* ctr_file_read(ctr_object* myself, ctr_argument* argumentList) { ctr_object* path = ctr_internal_object_find_property(myself, ctr_build_string("path",4), 0); ctr_object* str; ctr_size vlen, fileLen; char* pathString; char *buffer; FILE* f; if (path == NULL) return CtrStdNil; vlen = path->value.svalue->vlen; pathString = malloc(vlen + 1); memcpy(pathString, path->value.svalue->value, vlen); memcpy(pathString+vlen,"\0",1); f = fopen(pathString, "rb"); free(pathString); if (!f) { CtrStdError = ctr_build_string_from_cstring("Unable to open file.\0"); return CtrStdNil; } fseek(f, 0, SEEK_END); fileLen=ftell(f); fseek(f, 0, SEEK_SET); buffer=(char *)malloc(fileLen+1); if (!buffer){ printf("Out of memory\n"); fclose(f);exit(1); } fread(buffer, fileLen, 1, f); fclose(f); str = ctr_build_string(buffer, fileLen); free(buffer); return str; }
/** * StringFromTo * * Returns a portion of a string defined by from-to values. * This message is UTF-8 unicode aware. * * Usage: * 'hello' from: 2 to: 3. #ll */ ctr_object* ctr_string_fromto(ctr_object* myself, ctr_argument* argumentList) { ctr_object* fromPos = ctr_internal_cast2number(argumentList->object); ctr_object* toPos = ctr_internal_cast2number(argumentList->next->object); long len = myself->value.svalue->vlen; long a = (fromPos->value.nvalue); long b = (toPos->value.nvalue); long t; long ua, ub; char* dest; ctr_object* newString; if (b == a) return ctr_build_string("",0); if (a > b) { t = a; a = b; b = t; } if (a > len) return ctr_build_string("", 0); if (b > len) b = len; if (a < 0) a = 0; if (b < 0) return ctr_build_string("", 0); ua = getBytesUtf8(myself->value.svalue->value, 0, a); ub = getBytesUtf8(myself->value.svalue->value, ua, ((b - a))); dest = malloc(ub * sizeof(char)); memcpy(dest, (myself->value.svalue->value) + ua, ub); newString = ctr_build_string(dest,ub); return newString; }
/** * CTRWalkerAssignment * * Processes an assignment operation. */ ctr_object * ctr_cwlk_assignment (ctr_tnode * node) { char wasReturn = 0; ctr_tlistitem *assignmentItems = node->nodes; ctr_tnode *assignee = assignmentItems->node; ctr_tlistitem *valueListItem = assignmentItems->next; ctr_tnode *value = valueListItem->node; ctr_object *x; ctr_object *result; char ret; if (CtrStdFlow == NULL) { ctr_callstack[ctr_callstack_index++] = assignee; } x = ctr_cwlk_expr (value, &wasReturn); if (!x) { CtrStdFlow = ctr_build_string_from_cstring ("NULL expression"); return NULL; } if (assignee->type == CTR_AST_NODE_REFERENCE) { if (assignee->modifier == 1) { result = ctr_assign_value_to_my (ctr_build_string (assignee->value, assignee->vlen), x); } else if (assignee->modifier == 2) { result = ctr_assign_value_to_local (ctr_build_string (assignee->value, assignee->vlen), x); } else if (assignee->modifier == 3) { result = ctr_assign_value (ctr_build_string (assignee->value, assignee->vlen), x); //Handle lexical scoping } else { result = ctr_assign_value (ctr_build_string (assignee->value, assignee->vlen), x); } } else { int old_replace = ctr_cwlk_replace_refs; ctr_cwlk_replace_refs = 1; ctr_cwlk_last_msg_level = ctr_cwlk_msg_level; ctr_object *y = ctr_cwlk_expr (assignee, &ret); ctr_cwlk_replace_refs = old_replace; //set back in case we didn't reset result = ctr_send_message_variadic (x, "unpack:", 7, 1, y); ctr_object *old_result = NULL; while (old_result != result && result->info.type == CTR_OBJECT_TYPE_OTBLOCK) result = ctr_block_run_here (result, NULL, (old_result = result)); } if (CtrStdFlow == NULL) { ctr_callstack_index--; } return result; }
/** * CTRMessageSend * * Sends a message to a receiver object. */ ctr_object* ctr_send_message(ctr_object* receiverObject, char* message, long vlen, ctr_argument* argumentList) { char toParent = 0; ctr_object* me; ctr_object* methodObject; ctr_object* searchObject; ctr_argument* argCounter; ctr_argument* mesgArgument; ctr_object* result; ctr_object* (*funct)(ctr_object* receiverObject, ctr_argument* argumentList); int argCount; if (CtrStdError != NULL) return NULL; /* Error mode, ignore subsequent messages until resolved. */ methodObject = NULL; searchObject = receiverObject; if (vlen > 1 && message[0] == '`') { me = ctr_internal_object_find_property(ctr_contexts[ctr_context_id], ctr_build_string_from_cstring("me\0"), 0); if (searchObject == me) { toParent = 1; message = message + 1; vlen--; } } while(!methodObject) { methodObject = ctr_internal_object_find_property(searchObject, ctr_build_string(message, vlen), 1); if (methodObject && toParent) { toParent = 0; methodObject = NULL; } if (methodObject) break; if (!searchObject->link) break; searchObject = searchObject->link; } if (!methodObject) { argCounter = argumentList; argCount = 0; while(argCounter->next && argCount < 4) { argCounter = argCounter->next; argCount ++; } mesgArgument = CTR_CREATE_ARGUMENT(); mesgArgument->object = ctr_build_string(message, vlen); mesgArgument->next = argumentList; if (argCount == 0 || argCount > 2) { return ctr_send_message(receiverObject, "respondTo:", 10, mesgArgument); } else if (argCount == 1) { return ctr_send_message(receiverObject, "respondTo:with:", 15, mesgArgument); } else if (argCount == 2) { return ctr_send_message(receiverObject, "respondTo:with:and:", 19, mesgArgument); } } if (methodObject->info.type == CTR_OBJECT_TYPE_OTNATFUNC) { funct = methodObject->value.fvalue; result = funct(receiverObject, argumentList); } if (methodObject->info.type == CTR_OBJECT_TYPE_OTBLOCK) { result = ctr_block_run(methodObject, argumentList, receiverObject); } return result; }
/** * StringRightTrim */ ctr_object* ctr_string_rtrim(ctr_object* myself, ctr_argument* argumentList) { char* str = myself->value.svalue->value; long len = myself->value.svalue->vlen; long i = 0, end, tlen; char* tstr; if (len == 0) return ctr_build_string("", 0); i = len - 1; while(i > 0 && isspace(*(str+i))) i--; end = i + 1; tlen = end; tstr = malloc(tlen * sizeof(char)); memcpy(tstr, str, tlen); return ctr_build_string(tstr, tlen); }
/** * StringLeftTrim */ ctr_object* ctr_string_ltrim(ctr_object* myself, ctr_argument* argumentList) { char* str = myself->value.svalue->value; long len = myself->value.svalue->vlen; long i = 0, begin; long tlen; char* tstr; if (len == 0) return ctr_build_string("", 0); while(i < len && isspace(*(str+i))) i++; begin = i; i = len - 1; tlen = (len - begin); tstr = malloc(tlen * sizeof(char)); memcpy(tstr, str+begin, tlen); return ctr_build_string(tstr, tlen); }
/** * C-constructor function, as declared above. * * This function gets called when the plugin is loaded into memory. * Here you have a chance to add the new object(s) to the World. * * In our case, we are going to add the Percolator object to the * world. */ void begin(){ /* Create the Coffee Percolator Object - Use new, because its a prototype, not a class !*/ ctr_object* percolatorObject = ctr_percolator_new(CtrStdObject, NULL); /* Set the prototype */ percolatorObject->link = CtrStdObject; /* Add the method 'new' so people can create their percolators */ ctr_internal_create_func(percolatorObject, ctr_build_string("new", 3), &ctr_percolator_new); ctr_internal_create_func(percolatorObject, ctr_build_string("brew", 4), &ctr_percolator_brew); ctr_internal_create_func(percolatorObject, ctr_build_string("coffee:water:", 13), &ctr_percolator_add_coffee_water); /* Make the Percolator accessible to the world */ ctr_internal_object_add_property(CtrStdWorld, ctr_build_string("Percolator", 10), percolatorObject, CTR_CATEGORY_PUBLIC_PROPERTY); }
/** * [List] join: [String]. * * Joins the elements of a list together in a string * separated by a specified glue string. The example * code results in the string: '1,2,3'. * * Usage: * * collection := List new. * collection append: 1, append: 2, append 3. * collection join: ','. * * In other languages: * Dutch: [Reeks] samenvoegen: [Tekst] | Maakt een tekst door * reekselementen samen te voegen met gespecificeerde koppelteken(s). */ ctr_object* ctr_array_join(ctr_object* myself, ctr_argument* argumentList) { int i; char* result; ctr_size len = 0; ctr_size pos; ctr_object* o; ctr_object* str; ctr_object* resultStr; ctr_object* glue = ctr_internal_cast2string(argumentList->object); ctr_size glen = glue->value.svalue->vlen; for(i=myself->value.avalue->tail; i<myself->value.avalue->head; i++) { o = *( myself->value.avalue->elements + i ); str = ctr_internal_cast2string(o); pos = len; if (i == myself->value.avalue->tail) { len = str->value.svalue->vlen; result = ctr_heap_allocate(sizeof(char)*len); } else { len += str->value.svalue->vlen + glen; result = ctr_heap_reallocate(result, sizeof(char)*len ); memcpy(result+pos, glue->value.svalue->value, glen); pos += glen; } memcpy(result+pos, str->value.svalue->value, str->value.svalue->vlen); } resultStr = ctr_build_string(result, len); if (i > myself->value.avalue->tail) ctr_heap_free( result ); return resultStr; }
/** * CTRFindInMy * * Tries to locate a property of an object. */ ctr_object* ctr_find_in_my(ctr_object* key) { ctr_object* context = ctr_find(ctr_build_string("me",2)); ctr_object* foundObject = ctr_internal_object_find_property(context, key, 0); if (CtrStdError) return CtrStdNil; if (foundObject == NULL) { printf("Error, property not found: %s.\n", key->value.svalue->value); exit(1); } return foundObject; }
/** * CTRAssignValueObject * * Assigns a value to a property of an object. */ ctr_object* ctr_assign_value_to_my(ctr_object* key, ctr_object* o) { ctr_object* object; ctr_object* my = ctr_find(ctr_build_string("me", 2)); if (CtrStdError) return CtrStdNil; key->info.sticky = 0; if (o->info.type == CTR_OBJECT_TYPE_OTOBJECT || o->info.type == CTR_OBJECT_TYPE_OTMISC || o->info.type == CTR_OBJECT_TYPE_OTARRAY || o->info.type == CTR_OBJECT_TYPE_OTNIL) { ctr_internal_object_set_property(my, key, o, 0); } else { object = ctr_internal_create_object(o->info.type); object->properties = o->properties; object->methods = o->methods; object->link = o->link; object->info.sticky = 0; ctr_internal_object_set_property(my, key, object, 0); } /* depending on type, copy specific value */ if (o->info.type == CTR_OBJECT_TYPE_OTBOOL) { object->value.bvalue = o->value.bvalue; } else if (o->info.type == CTR_OBJECT_TYPE_OTNUMBER) { object->value.nvalue = o->value.nvalue; } else if (o->info.type == CTR_OBJECT_TYPE_OTSTRING) { object->value.svalue = malloc(sizeof(ctr_string)); object->value.svalue->value = malloc(sizeof(char)*o->value.svalue->vlen); memcpy(object->value.svalue->value, o->value.svalue->value,o->value.svalue->vlen); object->value.svalue->vlen = o->value.svalue->vlen; } else if (o->info.type == CTR_OBJECT_TYPE_OTBLOCK) { object->value.block = o->value.block; } return object; }
ctr_object* ctr_json_create_object(json_t* root, ctr_object* gt) { switch(json_typeof(root)) { case JSON_OBJECT: { ctr_object* sub = ctr_internal_create_object(CTR_OBJECT_TYPE_OTOBJECT); ctr_set_link_all(sub, gt); // size_t size; const char *key; json_t *value; ctr_argument* argl = ctr_heap_allocate(sizeof(*argl)); argl->next = ctr_heap_allocate(sizeof(*argl)); // size = json_object_size(root); json_object_foreach(root, key, value) { char* k = (char*)key; ctr_object* ko = ctr_build_string_from_cstring(k); ctr_object* vo = ctr_json_create_object(value, gt); argl->object = vo; argl->next->object = ko; sub = ctr_map_put(sub, argl); } ctr_heap_free(argl->next); ctr_heap_free(argl); return sub; } case JSON_ARRAY: { ctr_object* arr = ctr_array_new(CtrStdArray, NULL); ctr_argument* arg = ctr_heap_allocate(sizeof(ctr_argument)); size_t i; size_t size = json_array_size(root); for (i = 0; i < size; i++) { arg->object = ctr_json_create_object(json_array_get(root, i), gt); ctr_array_push(arr, arg); } ctr_heap_free(arg); return arr; } case JSON_STRING: { ctr_object* str = ctr_build_string((char*)json_string_value(root), json_string_length(root)); return str; } case JSON_INTEGER: { return ctr_build_number_from_float(json_integer_value(root)); } case JSON_REAL: { return ctr_build_number_from_float(json_real_value(root)); } case JSON_FALSE: { return ctr_build_bool(0); } case JSON_TRUE: { return ctr_build_bool(1); } case JSON_NULL: { return ctr_build_nil(); } default: { CtrStdFlow = ctr_build_string_from_cstring("Unrecognized JSON type"); return CtrStdNil; } }
/** * [Percolator] coffee: [Number] water: [Number] * * Adds coffee and water to the perculator. * * myPercolator := Percolator new. * cupOfCoffee := myPercolator coffee: 1 water: 2, brew. * */ ctr_object* ctr_percolator_add_coffee_water(ctr_object* myself, ctr_argument* argumentList) { ctr_internal_object_set_property( myself, ctr_build_string("coffee", 6), ctr_internal_cast2number(argumentList->object), CTR_CATEGORY_PRIVATE_PROPERTY ); ctr_internal_object_set_property( myself, ctr_build_string("water", 5), ctr_internal_cast2number(argumentList->next->object), CTR_CATEGORY_PRIVATE_PROPERTY ); return myself; }
/** * StringReplaceWith * * Replaces needle with replacement in original string and returns * the result as a new string object. * * Usage: * * 'LiLo BootLoader' replace: 'L' with: 'l'. #lilo Bootloader */ ctr_object* ctr_string_replace_with(ctr_object* myself, ctr_argument* argumentList) { ctr_object* needle = ctr_internal_cast2string(argumentList->object); ctr_object* replacement = ctr_internal_cast2string(argumentList->next->object); char* dest; char* odest; char* src = myself->value.svalue->value; char* ndl = needle->value.svalue->value; char* rpl = replacement->value.svalue->value; long hlen = myself->value.svalue->vlen; long nlen = needle->value.svalue->vlen; long rlen = replacement->value.svalue->vlen; long dlen = hlen; char* p; long i = 0; long offset = 0; long d; dest = (char*) malloc(dlen*sizeof(char)); odest = dest; if (nlen == 0 || hlen == 0) { return ctr_build_string(src, hlen); } while(1) { p = ctr_internal_memmem(src, hlen, ndl, nlen, 0); if (p == NULL) break; d = (dest - odest); if ((dlen - nlen + rlen)>dlen) { dlen = (dlen - nlen + rlen); odest = (char*) realloc(odest, dlen * sizeof(char)); dest = (odest + d); } else { dlen = (dlen - nlen + rlen); } offset = (p - src); memcpy(dest, src, offset); dest = dest + offset; memcpy(dest, rpl, rlen); dest = dest + rlen; hlen = hlen - (offset + nlen); src = src + (offset + nlen); i++; } memcpy(dest, src, hlen); return ctr_build_string(odest, dlen); }
ctr_object* ctr_string_to_lower(ctr_object* myself, ctr_argument* argumentList) { char* str = myself->value.svalue->value; size_t len = myself->value.svalue->vlen; char* tstr = malloc(len * sizeof(char)); int i=0; for(i =0; i < len; i++) { tstr[i] = tolower(str[i]); } return ctr_build_string(tstr, len); }
/** * File * * Represents a File object. * Creates a new file object based on the specified path. * * Usage: * * File new: '/example/path/to/file.txt'. */ ctr_object* ctr_file_new(ctr_object* myself, ctr_argument* argumentList) { ctr_object* s = ctr_object_make(myself, argumentList); ctr_object* pathObject; s->info.type = CTR_OBJECT_TYPE_OTEX; /* indicates resource for GC */ s->link = myself; s->value.rvalue = NULL; pathObject = ctr_build_string( argumentList->object->value.svalue->value, argumentList->object->value.svalue->vlen ); ctr_internal_object_add_property( s, ctr_build_string_from_cstring( "path" ), pathObject, 0 ); return s; }
/** * Percolator new * * Creates a new instance of the percolator object. * * Usage: * * myPercolator := Percolator new. * cupOfCoffee := myPercolator coffee: 1 water: 2, brew. * */ ctr_object* ctr_percolator_new(ctr_object* myself, ctr_argument* argumentList) { ctr_object* percolatorInstance = ctr_internal_create_object(CTR_OBJECT_TYPE_OTOBJECT); percolatorInstance->link = myself; ctr_internal_object_set_property( percolatorInstance, ctr_build_string("coffee", 6), ctr_build_number_from_float(0), CTR_CATEGORY_PRIVATE_PROPERTY ); ctr_internal_object_set_property( percolatorInstance, ctr_build_string("water", 5), ctr_build_number_from_float(0), CTR_CATEGORY_PRIVATE_PROPERTY ); return percolatorInstance; }
/** * BlockRun * * Runs a block of code. */ ctr_object* ctr_block_run(ctr_object* myself, ctr_argument* argList, ctr_object* my) { ctr_object* result; ctr_tnode* node = myself->value.block; ctr_tlistitem* codeBlockParts = node->nodes; ctr_tnode* codeBlockPart1 = codeBlockParts->node; ctr_tnode* codeBlockPart2 = codeBlockParts->next->node; ctr_tlistitem* parameterList = codeBlockPart1->nodes; ctr_tnode* parameter; ctr_object* a; ctr_open_context(); if (parameterList && parameterList->node) { parameter = parameterList->node; while(1) { if (parameter && argList->object) { a = argList->object; ctr_assign_value_to_local(ctr_build_string(parameter->value, parameter->vlen), a); } if (!argList->next) break; argList = argList->next; if (!parameterList->next) break; parameterList = parameterList->next; parameter = parameterList->node; } } ctr_assign_value_to_local(ctr_build_string("me",2), my); ctr_assign_value_to_local(ctr_build_string("thisBlock",9), myself); /* otherwise running block may get gc'ed. */ result = ctr_cwlk_run(codeBlockPart2); if (result == NULL) result = my; ctr_close_context(); if (CtrStdError != NULL && CtrStdError != CtrStdNil) { ctr_object* catchBlock = malloc(sizeof(ctr_object)); catchBlock = ctr_internal_object_find_property(myself, ctr_build_string("catch",5), 0); if (catchBlock != NULL) { ctr_argument* a = CTR_CREATE_ARGUMENT(); a->object = CtrStdError; CtrStdError = NULL; ctr_block_run(catchBlock, a, my); result = myself; } } return result; }
/** * [Map] [Key]: [Value] * * You can fill the map object with key-value pairs by sending any * binary or keyword message that is not part if its standard behaviour. * Likewise you can retrieve any value from the map by sending the corresponding key * as a unary message. This allows for a very natural looking notation to create * and modify map objects. * * Usage: * * ☞ menu := Map new * Margherita: 11.90, * Hawaii: 12.99, * QuattroFormaggi: 13.00. * * ✎ write: ( menu ? 'Hawaii' ), brk. * ✎ write: ( menu Margherita ), brk. * * In other languages: * * Dutch: [Lijst] [Object]: [Object] * Snelle en leesbare notatie om objecten toe te voegen aan een lijst. * Elk bericht dat niet wordt herkend wordt door de lijst als een * sleutel beschouwd, het opvolgende object zal op de plek worden * gezet in de lijst die door de sleutel wordt aangegeven. Dus om een * menukaart te vullen kan men zeggen: * * ☞ menu := Lijst nieuw. * menu pannekoek: 10. (hier kopppelen we pannekoek aan 10) * * Om nu op te vragen hoeveel een pannekoek kost schrijven we: * ☞ prijs := menu pannekoek. */ ctr_object* ctr_map_key_value(ctr_object* myself, ctr_argument* argumentList) { ctr_object* newKey; ctr_object* key = ctr_internal_cast2string(argumentList->object); newKey = key; if (key->value.svalue->vlen>1) { newKey = ctr_build_string(key->value.svalue->value,key->value.svalue->vlen-1); } argumentList->object = argumentList->next->object; argumentList->next->object = newKey; return ctr_map_put( myself, argumentList ); }
ctr_object* ctr_string_skip(ctr_object* myself, ctr_argument* argumentList) { ctr_argument* argument1; ctr_argument* argument2; if (myself->value.svalue->vlen < argumentList->object->value.nvalue) return ctr_build_string("",0); argument1 = CTR_CREATE_ARGUMENT(); argument2 = CTR_CREATE_ARGUMENT(); argument1->object = argumentList->object; argument1->next = argument2; argument2->object = ctr_build_number_from_float(myself->value.svalue->vlen - argumentList->object->value.nvalue); return ctr_string_from_length(myself, argument1); }
/** * StringCharacterAt * * Returns the character at the specified position (UTF8 aware). * * Usage: * ('hello' at: 2). #l */ ctr_object* ctr_string_at(ctr_object* myself, ctr_argument* argumentList) { ctr_object* fromPos = ctr_internal_cast2number(argumentList->object); long a = (fromPos->value.nvalue); long ua = getBytesUtf8(myself->value.svalue->value, 0, a); long ub = getBytesUtf8(myself->value.svalue->value, ua, 1); ctr_object* newString; char* dest = malloc(ub * sizeof(char)); memcpy(dest, (myself->value.svalue->value) + ua, ub); newString = ctr_build_string(dest,ub); return newString; }
/** * [File] run * * Includes the file as a piece of executable code. */ ctr_object* ctr_file_include_ast(ctr_object* myself, ctr_argument* argumentList) { ctr_object* path = ctr_internal_object_find_property(myself, ctr_build_string("path",4), 0); ctr_tnode* parsedCode; ctr_size vlen; char* pathString; if (path == NULL) return myself; vlen = path->value.svalue->vlen; pathString = malloc(vlen + 1); memcpy(pathString, path->value.svalue->value, vlen); memcpy(pathString+vlen,"\0",1); parsedCode = ctr_serializer_unserialize(pathString); ctr_cwlk_run(parsedCode); return myself; }
/** * StringSplit * * Converts a string to an array by splitting the string using * the specified delimiter (also a string). */ ctr_object* ctr_string_split(ctr_object* myself, ctr_argument* argumentList) { char* str = myself->value.svalue->value; long len = myself->value.svalue->vlen; ctr_object* delimObject = ctr_internal_cast2string(argumentList->object); char* dstr = delimObject->value.svalue->value; long dlen = delimObject->value.svalue->vlen; ctr_argument* arg; char* elem; ctr_object* arr = ctr_array_new(CtrStdArray, NULL); long i; long j = 0; char* buffer = malloc(sizeof(char)*len); for(i=0; i<len; i++) { buffer[j] = str[i]; j++; if (ctr_internal_memmem(buffer, j, dstr, dlen, 0)!=NULL) { elem = malloc(sizeof(char)*(j-dlen)); memcpy(elem,buffer,j-dlen); arg = malloc(sizeof(ctr_argument)); arg->object = ctr_build_string(elem, j-dlen); ctr_array_push(arr, arg); free(arg); j=0; } } if (j>0) { elem = malloc(sizeof(char)*j); memcpy(elem,buffer,j); arg = malloc(sizeof(ctr_argument)); arg->object = ctr_build_string(elem, j); ctr_array_push(arr, arg); free(arg); } free(buffer); return arr; }
/** * StringConcat * * Appends other string to self and returns the resulting * string as a new object. */ ctr_object* ctr_string_concat(ctr_object* myself, ctr_argument* argumentList) { ctr_object* strObject = ctr_internal_create_object(CTR_OBJECT_TYPE_OTSTRING); ctr_size n1; ctr_size n2; char* dest; ctr_object* newString; strObject = ctr_internal_cast2string(argumentList->object); n1 = myself->value.svalue->vlen; n2 = strObject->value.svalue->vlen; dest = calloc(sizeof(char), (n1 + n2)); memcpy(dest, myself->value.svalue->value, n1); memcpy(dest+n1, strObject->value.svalue->value, n2); newString = ctr_build_string(dest, (n1 + n2)); return newString; }
/** * File * * Represents a File object. * Creates a new file object based on the specified path. * * Usage: * * File new: '/example/path/to/file.txt'. */ ctr_object* ctr_file_new(ctr_object* myself, ctr_argument* argumentList) { ctr_object* s = ctr_object_make(myself, argumentList); ctr_object* pathObject; s->info.type = CTR_OBJECT_TYPE_OTMISC; s->link = myself; s->value.rvalue = malloc(sizeof(ctr_resource)); s->value.rvalue->type = 1; pathObject = ctr_internal_create_object(CTR_OBJECT_TYPE_OTSTRING); pathObject->info.type = CTR_OBJECT_TYPE_OTSTRING; pathObject->value.svalue = (ctr_string*) malloc(sizeof(ctr_string)); pathObject->value.svalue->value = (char*) malloc(sizeof(char) * argumentList->object->value.svalue->vlen); memcpy(pathObject->value.svalue->value, argumentList->object->value.svalue->value, argumentList->object->value.svalue->vlen); pathObject->value.svalue->vlen = argumentList->object->value.svalue->vlen; ctr_internal_object_add_property(s, ctr_build_string("path",4), pathObject, 0); return s; }
/** * StringHTMLEscape * * Escapes HTML chars. */ ctr_object* ctr_string_html_escape(ctr_object* myself, ctr_argument* argumentList) { char* str = myself->value.svalue->value; long len = myself->value.svalue->vlen; char* tstr = malloc(len * sizeof(char)); long i=0; long j=0; long k=0; long rlen; long tlen = len; char* replacement; for(i =0; i < len; i++) { char c = str[i]; if (c == '<') { replacement = "<"; rlen = 4; tlen += (rlen - 1); tstr = realloc(tstr, (tlen) * sizeof(char)); for(j=0; j<rlen; j++) tstr[k+j]=replacement[j]; k += rlen; } else if (c == '>') { replacement = ">"; rlen = 4; tlen += (rlen - 1); tstr = realloc(tstr, (tlen) * sizeof(char)); for(j=0; j<rlen; j++) tstr[k+j]=replacement[j]; k += rlen; } else if (c == '&') { replacement = "&"; rlen = 5; tlen += (rlen - 1); tstr = realloc(tstr, (tlen) * sizeof(char)); for(j=0; j<rlen; j++) tstr[k+j]=replacement[j]; k += rlen; } else if (c == '"') { replacement = """; rlen = 6; tlen += (rlen - 1); tstr = realloc(tstr, (tlen) * sizeof(char)); for(j=0; j<rlen; j++) tstr[k+j]=replacement[j]; k += rlen; } else { tstr[k++] = str[i]; } } return ctr_build_string(tstr, tlen); }
/** * [File] delete * * Deletes the file. */ ctr_object* ctr_file_delete(ctr_object* myself, ctr_argument* argumentList) { ctr_object* path = ctr_internal_object_find_property(myself, ctr_build_string("path",4), 0); ctr_size vlen; char* pathString; int r; if (path == NULL) return myself; vlen = path->value.svalue->vlen; pathString = malloc(vlen + 1); memcpy(pathString, path->value.svalue->value, vlen); memcpy(pathString+vlen,"\0",1); r = remove(pathString); if (r!=0) { CtrStdError = ctr_build_string_from_cstring("Unable to delete file.\0"); return CtrStdNil; } return myself; }
/** * InternalStringCast * * Casts an object to a string object. */ ctr_object* ctr_internal_cast2string( ctr_object* o ) { int slen; char* s; if (o->info.type == CTR_OBJECT_TYPE_OTSTRING) return o; else if (o->info.type == CTR_OBJECT_TYPE_OTNIL) { return ctr_build_string("[Nil]", 5); } else if (o->info.type == CTR_OBJECT_TYPE_OTBOOL && o->value.bvalue == 1) { return ctr_build_string("[True]", 6); } else if (o->info.type == CTR_OBJECT_TYPE_OTBOOL && o->value.bvalue == 0) { return ctr_build_string("[False]", 7); } else if (o->info.type == CTR_OBJECT_TYPE_OTNUMBER) { s = calloc(80, sizeof(char)); CTR_CONVFP(s,o->value.nvalue); slen = strlen(s); return ctr_build_string(s, slen); } else if (o->info.type == CTR_OBJECT_TYPE_OTBLOCK) { return ctr_build_string("[Block]",7);} else if (o->info.type == CTR_OBJECT_TYPE_OTOBJECT) { return ctr_build_string("[Object]",8);} return ctr_build_string("[?]", 3); }