/** * 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; }
/** * 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; }
/** * @internal * * Reads a server option set by user. */ ctr_object* ctr_request_internal_option(ctr_object* myself, char* optName) { ctr_object* key; ctr_object* val; key = ctr_build_string_from_cstring(optName); val = ctr_internal_object_find_property(myself, key, CTR_CATEGORY_PRIVATE_PROPERTY); return val; }
/** * [Map] at: [Key] * * Retrieves the value specified by the key from the map. * * In other languages: * Dutch: [Lijst] bij: [Object] | Geeft de waarde bij de bijbehorende sleutel. */ ctr_object* ctr_map_get(ctr_object* myself, ctr_argument* argumentList) { ctr_argument* emptyArgumentList; ctr_object* searchKey; ctr_object* foundObject; emptyArgumentList = ctr_heap_allocate(sizeof(ctr_argument)); emptyArgumentList->next = NULL; emptyArgumentList->object = NULL; searchKey = argumentList->object; /* Give developer a chance to define a key for array */ searchKey = ctr_send_message(searchKey, CTR_DICT_TOSTRING, strlen(CTR_DICT_TOSTRING), emptyArgumentList); ctr_heap_free( emptyArgumentList ); /* If developer returns something other than string (ouch, toString), then cast anyway */ if (searchKey->info.type != CTR_OBJECT_TYPE_OTSTRING) { searchKey = ctr_internal_cast2string(searchKey); } foundObject = ctr_internal_object_find_property(myself, searchKey, 0); if (foundObject == NULL) foundObject = ctr_build_nil(); return foundObject; }
/** * [File] read * * Reads contents of a file. Send this message to a file to read the entire contents in * one go. For big files you might want to prefer a streaming approach to avoid * memory exhaustion (see readBytes etc). * * Usage: * * data := File new: '/path/to/mydata.csv', read. * * In the example above we read the contents of the entire CSV file callled mydata.csv * in the variable called data. */ ctr_object* ctr_file_read(ctr_object* myself, ctr_argument* argumentList) { ctr_object* path = ctr_internal_object_find_property(myself, ctr_build_string_from_cstring( "path" ), 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 = ctr_heap_allocate( sizeof(char) * ( vlen + 1 ) ); memcpy(pathString, path->value.svalue->value, vlen); memcpy(pathString+vlen,"\0",1); f = fopen(pathString, "rb"); ctr_heap_free( pathString ); if (!f) { CtrStdFlow = ctr_build_string_from_cstring( "Unable to open file." ); CtrStdFlow->info.sticky = 1; return CtrStdNil; } fseek(f, 0, SEEK_END); fileLen=ftell(f); fseek(f, 0, SEEK_SET); buffer=(char *)ctr_heap_allocate(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); ctr_heap_free( buffer ); return str; }
/** * CTRFind * * Tries to locate a variable in the current context or one * of the contexts beneath. */ ctr_object* ctr_find(ctr_object* key) { int i = ctr_context_id; ctr_object* foundObject = NULL; if (CtrStdError) return CtrStdNil; while((i>-1 && foundObject == NULL)) { ctr_object* context = ctr_contexts[i]; foundObject = ctr_internal_object_find_property(context, key, 0); i--; } if (foundObject == NULL) { ctr_internal_plugin_find(key); foundObject = ctr_internal_object_find_property(CtrStdWorld, key, 0); } if (foundObject == NULL) { char* cstr; CTR_2CSTR(cstr, key); printf("Error, key not found: [%s].\n", cstr); exit(1); } return foundObject; }
/** * [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; }
/** * [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; }
/** * [File] exists * * Returns True if the file exists and False otherwise. */ ctr_object* ctr_file_exists(ctr_object* myself, ctr_argument* argumentList) { ctr_object* path = ctr_internal_object_find_property(myself, ctr_build_string_from_cstring( "path" ), 0); ctr_size vlen; char* pathString; FILE* f; int exists; if (path == NULL) return ctr_build_bool(0); vlen = path->value.svalue->vlen; pathString = ctr_heap_allocate(vlen + 1); memcpy(pathString, path->value.svalue->value, vlen); memcpy(pathString+vlen,"\0",1); f = fopen(pathString, "r"); ctr_heap_free( pathString ); exists = (f != NULL ); if (f) { fclose(f); } return ctr_build_bool(exists); }
/** * CTRSetBasic * * Sets a proeprty in an object (context). */ void ctr_set(ctr_object* key, ctr_object* object) { int i = ctr_context_id; ctr_object* context; ctr_object* foundObject = NULL; if (ctr_contexts[ctr_context_id] == CtrStdWorld) { ctr_internal_object_set_property(ctr_contexts[ctr_context_id], key, object, 0); return; } while((i>-1 && foundObject == NULL)) { context = ctr_contexts[i]; foundObject = ctr_internal_object_find_property(context, key, 0); if (foundObject) break; i--; } if (!foundObject) { printf("Error, cannot assign, key not found: %s, forgot to use var ?\n", key->value.svalue->value); exit(1); } ctr_internal_object_set_property(context, key, object, 0); }
/** * [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_from_cstring( "path" ), 0); ctr_size vlen; char* pathString; int r; if (path == NULL) return myself; vlen = path->value.svalue->vlen; pathString = ctr_heap_allocate( sizeof( char ) * ( vlen + 1 ) ); memcpy(pathString, path->value.svalue->value, vlen); memcpy(pathString+vlen,"\0",1); r = remove(pathString); ctr_heap_free( pathString ); if (r!=0) { CtrStdFlow = ctr_build_string_from_cstring( "Unable to delete file." ); CtrStdFlow->info.sticky = 1; return CtrStdNil; } return myself; }
/** * 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; }
/** * [File] include * * Includes the file as a piece of executable code. */ ctr_object* ctr_file_include(ctr_object* myself, ctr_argument* argumentList) { ctr_object* path = ctr_internal_object_find_property(myself, ctr_build_string_from_cstring( "path" ), 0); ctr_tnode* parsedCode; ctr_size vlen; char* pathString; char* prg; uint64_t program_size = 0; if (path == NULL) return myself; vlen = path->value.svalue->vlen; pathString = ctr_heap_allocate_tracked(sizeof(char)*(vlen+1)); //needed until end, pathString appears in stracktrace memcpy(pathString, path->value.svalue->value, vlen); memcpy(pathString+vlen,"\0",1); prg = ctr_internal_readf(pathString, &program_size); parsedCode = ctr_cparse_parse(prg, pathString); ctr_heap_free( prg ); ctr_cwlk_subprogram++; ctr_cwlk_run(parsedCode); ctr_cwlk_subprogram--; return myself; }
/** * [File] write: [String] * * Writes content to a file. */ ctr_object* ctr_file_write(ctr_object* myself, ctr_argument* argumentList) { ctr_object* str = ctr_internal_cast2string(argumentList->object); ctr_object* path = ctr_internal_object_find_property(myself, ctr_build_string("path",4), 0); FILE* f; ctr_size vlen; char* pathString; 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, "wb+"); free(pathString); if (!f) { CtrStdError = ctr_build_string_from_cstring("Unable to open file.\0"); return CtrStdNil; } fwrite(str->value.svalue->value, sizeof(char), str->value.svalue->vlen, f); fclose(f); return myself; }
/** * [File] size * * Returns the size of the file. */ ctr_object* ctr_file_size(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; FILE* f; int prev, sz; if (path == NULL) return ctr_build_number_from_float(0); vlen = path->value.svalue->vlen; pathString = malloc(vlen + 1); memcpy(pathString, path->value.svalue->value, vlen); memcpy(pathString+vlen,"\0",1); f = fopen(pathString, "r"); if (f == NULL) return ctr_build_number_from_float(0); prev = ftell(f); fseek(f, 0L, SEEK_END); sz=ftell(f); fseek(f,prev,SEEK_SET); if (f) { fclose(f); } return ctr_build_number_from_float( (ctr_number) sz ); }
/** * [File] open: [string] * * Open a file with using the specified mode. * * Usage: * * f := File new: '/path/to/file'. * f open: 'r+'. #opens file for reading and writing * * The example above opens the file in f for reading and writing. */ ctr_object* ctr_file_open(ctr_object* myself, ctr_argument* argumentList) { ctr_object* pathObj = ctr_internal_object_find_property(myself, ctr_build_string_from_cstring( "path" ), 0); char* mode; char* path; FILE* handle; ctr_resource* rs = ctr_heap_allocate(sizeof(ctr_resource)); ctr_object* modeStrObj = ctr_internal_cast2string( argumentList->object ); if ( myself->value.rvalue != NULL ) { ctr_heap_free( rs ); CtrStdFlow = ctr_build_string_from_cstring( "File has already been opened." ); CtrStdFlow->info.sticky = 1; return myself; } if ( pathObj == NULL ) return myself; path = ctr_heap_allocate_cstring( pathObj ); mode = ctr_heap_allocate_cstring( modeStrObj ); handle = fopen(path,mode); ctr_heap_free( path ); ctr_heap_free( mode ); rs->type = 1; rs->ptr = handle; myself->value.rvalue = rs; return myself; }
/** * [Percolator] brew * * Tries to brew some delicious coffee. * To brew one cup of coffee the Percolator needs two cups of water * and one spoon of coffee grounds. * * Read the inline comments to learn how to extend Citrine! */ ctr_object* ctr_percolator_brew(ctr_object* myself, ctr_argument* argumentList) { /** * Fetch the coffee property, note that the key is a Citrine String object. */ ctr_object* coffee = ctr_internal_object_find_property( myself, /* owner object */ ctr_build_string_from_cstring( "coffee" ), /* key object */ CTR_CATEGORY_PRIVATE_PROPERTY ); /** * Fetch the water property. */ ctr_object* water = ctr_internal_object_find_property( myself, ctr_build_string_from_cstring( "water" ), CTR_CATEGORY_PRIVATE_PROPERTY ); /** * To access a value: * * - numeric values reside in value.nvalue * - boolean values reside in value.bvalue * - array values reside in value.avalue (see ctr_collection) * - string values reside in value.svalue (see ctr_string) * - block values reside in value.block (see ctr_tnode) * - native functions in value.fvalue */ if (coffee->value.nvalue < 1) { return ctr_build_string_from_cstring( "No more coffee." ); } if (water->value.nvalue < 2) { return ctr_build_string_from_cstring( "No more water." ); } coffee->value.nvalue -= 1; water->value.nvalue -= 2; /** * To set a property of an object, use * the set_property function. */ ctr_internal_object_set_property( myself, ctr_build_string_from_cstring( "coffee" ), coffee, CTR_CATEGORY_PRIVATE_PROPERTY ); ctr_internal_object_set_property( myself, ctr_build_string_from_cstring( "water" ), water, CTR_CATEGORY_PRIVATE_PROPERTY ); return ctr_build_string_from_cstring( "Coffee!" ); }
/** * [File] path * * Returns the path of a file. The file object will respond to this * message by returning a string object describing the full path to the * recipient. */ ctr_object* ctr_file_path(ctr_object* myself, ctr_argument* argumentList) { ctr_object* path = ctr_internal_object_find_property(myself, ctr_build_string_from_cstring( "path" ), 0); if (path == NULL) return CtrStdNil; return path; }