static void push_str(struct context *context, struct byte_array *program) { struct byte_array* str = serial_decode_string(program); VM_DEBUGPRINT("STR '%s'\n", byte_array_to_string(str)); struct variable* v = variable_new_str(context, str); variable_push(context, v); }
static inline struct variable *cfnc_serialize(struct context *context) { struct variable *args = (struct variable*)stack_pop(context->operand_stack); struct variable *indexable = (struct variable*)array_get(args->list.ordered, 0); struct byte_array *bits = variable_serialize(context, NULL, indexable); byte_array_reset(bits); struct variable *result = variable_new_str(context, bits); byte_array_del(bits); return result; }
struct variable *sys_send(struct context *context) { struct variable *arguments = (struct variable*)stack_pop(context->operand_stack); struct variable *sender = (struct variable*)array_get(arguments->list, 1); const char *message = param_str(arguments, 2); assert_message(sender->type == VAR_INT, "non int fd"); int32_t fd = sender->integer; struct thread_argument *ta = (struct thread_argument*)map_get(socket_listeners, (void*)(VOID_INT)fd); printf("send on ssl=%p\n", ta->ssl); if (CyaSSL_write(ta->ssl, message, strlen(message)) != strlen(message)) context->vm_exception = variable_new_str(context, byte_array_from_string("CyaSSL_write error")); return NULL; }
// a b c // <sought> <replacement> [<start>] // <start> <length> <replacement> static inline struct variable *cfnc_replace(struct context *context) { struct variable *args = (struct variable*)stack_pop(context->operand_stack); struct variable *self = (struct variable*)array_get(args->list.ordered, 0); struct variable *a = (struct variable*)array_get(args->list.ordered, 1); struct variable *b = (struct variable*)array_get(args->list.ordered, 2); struct variable *c = args->list.ordered->length > 3 ? (struct variable*)array_get(args->list.ordered, 3) : NULL; null_check(self); null_check(b); assert_message(self->type == VAR_STR, "searching in a non-string"); struct byte_array *replaced = NULL; if (a->type == VAR_STR) { // find a, replace with b assert_message(b->type == VAR_STR, "non-string replacement"); int32_t where = 0; if (c) { // replace first match after index c assert_message(c->type == VAR_INT, "non-integer index"); if (((where = byte_array_find(self->str, a->str, c->integer)) >= 0)) replaced = byte_array_replace(self->str, b->str, where, b->str->length); } else { replaced = byte_array_replace_all(self->str, a->str, b->str); } } else if (a->type == VAR_INT ) { // replace at index a, length b, insert c assert_message(a || a->type == VAR_INT, "non-integer count"); assert_message(b || b->type == VAR_INT, "non-integer start"); replaced = byte_array_replace(self->str, c->str, a->integer, b->integer); } else exit_message("replacement is not a string"); null_check(replaced); struct variable *result = variable_new_str(context, replaced); byte_array_del(replaced); return result; }
static struct variable *binary_op_str(struct context *context, enum Opcode op, struct variable *u, struct variable *v) { struct variable *w = NULL; struct byte_array *ustr = u->type == VAR_STR ? u->str : variable_value(context, u); struct byte_array *vstr = v->type == VAR_STR ? v->str : variable_value(context, v); switch (op) { case VM_ADD: w = variable_new_str(context, byte_array_concatenate(2, vstr, ustr)); break; case VM_EQU: w = variable_new_int(context, byte_array_equals(ustr, vstr)); break; default: return (struct variable*)vm_exit_message(context, "unknown string operation"); } return w; }
// returns contents and modification time of file struct variable *sys_read(struct context *context) { struct variable *args = (struct variable*)stack_pop(context->operand_stack); struct variable *path = param_var(args, 1); uint32_t offset = param_int(args, 2); uint32_t length = param_int(args, 3); struct byte_array *bytes = read_file(path->str, offset, length); DEBUGPRINT("read %d bytes\n", bytes ? bytes->length : 0); struct variable *content = NULL; if (NULL != bytes) { content = variable_new_str(context, bytes); byte_array_del(bytes); } else { context->error = variable_new_str_chars(context, "could not load file"); content = variable_new_nil(context); } return content; }
static struct variable *list_get_int(struct context *context, const struct variable *indexable, uint32_t index) { null_check(indexable); enum VarType it = (enum VarType)indexable->type; switch (it) { case VAR_INT: return variable_new_int(context, index); case VAR_LST: if (index < indexable->list->length) return (struct variable*)array_get(indexable->list, index); return variable_new_nil(context); case VAR_STR: { vm_assert(context, index < indexable->str->length, "index out of bounds"); char *str = (char*)malloc(2); sprintf(str, "%c", indexable->str->data[index]); return variable_new_str(context, byte_array_from_string(str)); } default: vm_exit_message(context, "indexing non-indexable"); return NULL; } }
struct variable *builtin_method(struct context *context, struct variable *indexable, const struct variable *index) { enum VarType it = indexable->type; char *idxstr = byte_array_to_string(index->str); struct variable *result = NULL; if (!strcmp(idxstr, FNC_LENGTH)) { int n; switch (indexable->type) { case VAR_LST: n = indexable->list.ordered->length; break; case VAR_STR: n = indexable->str->length; break; case VAR_NIL: n = 0; break; default: free(idxstr); exit_message("no length for non-indexable"); return NULL; } result = variable_new_int(context, n); } else if (!strcmp(idxstr, FNC_TYPE)) { const char *typestr = var_type_str(it); result = variable_new_str_chars(context, typestr); } else if (!strcmp(idxstr, FNC_STRING)) { switch (indexable->type) { case VAR_STR: case VAR_BYT: case VAR_FNC: result = variable_copy(context, indexable); break; default: { struct byte_array *vv = variable_value(context, indexable); result = variable_new_str(context, vv); byte_array_del(vv); break; } } } else if (!strcmp(idxstr, FNC_LIST)) result = variable_new_list(context, indexable->list.ordered); else if (!strcmp(idxstr, FNC_KEY)) { if (indexable->type == VAR_KVP) result = indexable->kvp.key; else result = variable_new_nil(context); } else if (!strcmp(idxstr, FNC_VAL)) { if (indexable->type == VAR_KVP) result = indexable->kvp.val; else result = variable_new_nil(context); } else if (!strcmp(idxstr, FNC_KEYS)) result = variable_map_list(context, indexable, &map_keys); else if (!strcmp(idxstr, FNC_VALS)) result = variable_map_list(context, indexable, &map_vals); else if (!strcmp(idxstr, FNC_PACK)) result = variable_new_cfnc(context, &cfnc_pack); else if (!strcmp(idxstr, FNC_SERIALIZE)) result = variable_new_cfnc(context, &cfnc_serialize); else if (!strcmp(idxstr, FNC_DESERIALIZE)) result = variable_new_cfnc(context, &cfnc_deserialize); else if (!strcmp(idxstr, FNC_SORT)) { assert_message(indexable->type == VAR_LST, "sorting non-list"); result = variable_new_cfnc(context, &cfnc_sort); } else if (!strcmp(idxstr, FNC_CHAR)) result = variable_new_cfnc(context, &cfnc_char); else if (!strcmp(idxstr, FNC_HAS)) result = variable_new_cfnc(context, &cfnc_has); else if (!strcmp(idxstr, FNC_FIND)) result = variable_new_cfnc(context, &cfnc_find); else if (!strcmp(idxstr, FNC_PART)) result = variable_new_cfnc(context, &cfnc_part); else if (!strcmp(idxstr, FNC_REMOVE)) result = variable_new_cfnc(context, &cfnc_remove); else if (!strcmp(idxstr, FNC_INSERT)) result = variable_new_cfnc(context, &cfnc_insert); else if (!strcmp(idxstr, FNC_REPLACE)) result = variable_new_cfnc(context, &cfnc_replace); free(idxstr); return result; }
struct variable *sys_connect(struct context *context) { struct variable *arguments = (struct variable*)stack_pop(context->operand_stack); const char *serveraddr = param_str(arguments, 1); const int32_t serverport = param_int(arguments, 2); struct variable *listener = ((struct variable*)array_get(arguments->list, 2)); int sockfd; struct sockaddr_in servaddr; CYASSL_CTX* ctx; CYASSL* ssl; node_init(); // Create and initialize CYASSL_CTX structure if ( (ctx = CyaSSL_CTX_new(CyaTLSv1_client_method())) == NULL) { context->vm_exception = variable_new_str(context, byte_array_from_string("SSL_CTX_new error")); CyaSSL_Cleanup(); return NULL; } // Load CA certificates into CYASSL_CTX if (CyaSSL_CTX_load_verify_locations(ctx, "./conf/ca-cert.pem", 0) != SSL_SUCCESS) { context->vm_exception = variable_new_str(context, byte_array_from_string("Error loading ca-cert.pem, please check the file.\n")); CyaSSL_CTX_free(ctx); CyaSSL_Cleanup(); return NULL; } // Create Socket file descriptor sockfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(serverport); inet_pton(AF_INET, serveraddr, &servaddr.sin_addr); // Blocking Connect to socket file descriptor connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)); // Create CYASSL object if ((ssl = CyaSSL_new(ctx)) == NULL) { context->vm_exception = variable_new_str(context, byte_array_from_string("CyaSSL_new error")); CyaSSL_CTX_free(ctx); CyaSSL_Cleanup(); return NULL; } CyaSSL_set_fd(ssl, sockfd); fprintf(stderr, "Connected on %d -- %p\n", sockfd, ssl); struct thread_argument *ta = (struct thread_argument *)malloc(sizeof(struct thread_argument)); ta->find = context->find; ta->listener = listener; ta->ssl = ssl; ta->fd = sockfd; ta->cya = ctx; if (socket_listeners == NULL) socket_listeners = map_new_ex(NULL, &int_compare, &int_hash, &int_copy, &int_del); map_insert(socket_listeners, (void*)(VOID_INT)sockfd, (void*)(VOID_INT)ta); return variable_new_int(context, sockfd); }