// this is the fn parameter passed into file_list() int file_list_callback(const char *path, bool dir, long mod, void *fl_context) { // -> / path = remove_substring(path, "//"); //printf("file_list_callback %s\n", path); size_t size = file_size(path); path = remove_substring(path, hal_doc_path(NULL)); struct file_list_context *flc = (struct file_list_context*)fl_context; struct variable *path3 = variable_new_str_chars(flc->context, path); struct variable *key2 = variable_new_str_chars(flc->context, RESERVED_DIR); struct variable *value = variable_new_bool(flc->context, dir); struct variable *metadata = variable_new_list(flc->context, NULL); variable_map_insert(flc->context, metadata, key2, value); key2 = variable_new_str_chars(flc->context, RESERVED_MODIFIED); value = variable_new_int(flc->context, (int32_t)mod); variable_map_insert(flc->context, metadata, key2, value); variable_map_insert(flc->context, flc->result, path3, metadata); key2 = variable_new_str_chars(flc->context, RESERVED_SIZE); value = variable_new_int(flc->context, (int32_t)size); variable_map_insert(flc->context, metadata, key2, value); variable_map_insert(flc->context, flc->result, path3, metadata); return 0; }
struct variable *ui_result(struct context *context, void *widget, int32_t w, int32_t h) { struct variable *widget2 = variable_new_void(context, widget); variable_push(context, widget2); variable_push(context, variable_new_int(context, w)); variable_push(context, variable_new_int(context, h)); return variable_new_src(context, 3); }
struct variable *sys_now(struct context *context) { stack_pop(context->operand_stack); // sys struct timeval tv; struct timezone tzp; if (gettimeofday(&tv, &tzp)) { perror("gettimeofday"); return variable_new_int(context, 0); } return variable_new_int(context, tv.tv_usec); }
struct variable *sys_window(struct context *context) { struct variable *value = (struct variable*)stack_pop(context->operand_stack); struct variable *uictx = param_var(value, 1); struct variable *logic = param_var(value, 2); context->singleton->keepalive = true; // so that context_del isn't called when UI is active int32_t w=0, h=0; hal_window(context, uictx, &w, &h, logic); variable_push(context, variable_new_int(context, w)); variable_push(context, variable_new_int(context, h)); return variable_new_src(context, 2); }
static void unary_op(struct context *context, enum Opcode op) { if (!context->runtime) VM_DEBUGPRINT("%s\n", NUM_TO_STRING(opcodes, op)); struct variable *v = (struct variable*)variable_pop(context); struct variable *result = NULL; switch (v->type) { case VAR_NIL: { switch (op) { case VM_NEG: result = variable_new_nil(context); break; case VM_NOT: result = variable_new_bool(context, true); break; default: vm_exit_message(context, "bad math operator"); break; } } break; case VAR_INT: { int32_t n = v->integer; switch (op) { case VM_NEG: result = variable_new_int(context, -n); break; case VM_NOT: result = variable_new_bool(context, !n); break; case VM_INV: result = variable_new_int(context, ~n); break; default: vm_exit_message(context, "bad math operator"); break; } } break; case VAR_FLT: { float n = v->floater; switch (op) { case VM_NEG: result = variable_new_float(context, -n); break; case VM_NOT: result = variable_new_bool(context, !n); break; default: vm_exit_message(context, "bad math operator"); break; } } break; default: if (op == VM_NOT) result = variable_new_bool(context, false); else vm_exit_message(context, "bad math type"); break; } variable_push(context, result); DEBUGPRINT("%s(%s) = %s\n", NUM_TO_STRING(opcodes, op), variable_value_str(context, v), variable_value_str(context, result)); }
struct variable *sys_forkexec(struct context *context) { struct variable *args = (struct variable*)stack_pop(context->operand_stack); bool wait = param_bool(args, 1); const char *app = param_str(args, 2); uint32_t argc = args->list.ordered->length - 3; char **argv = malloc(sizeof(char*) * (argc+1)); for (int i=2; i<argc+3; i++) { //printf("arg %d/%D = %s\n", i-2, argc, param_str(args, i)); argv[i-2] = param_str(args, i); } argv[argc+1] = NULL; pid_t pid = fork(); if (pid < 0) perror("fork"); else if (pid == 0) // child { if (execv(app, argv) < 0) perror("execv"); printf("fork child exit\n"); exit(0); } else if (wait) // parent waits for child to finish { int status; if (waitpid(pid, &status, 0) != pid) perror("waitpid"); } return variable_new_int(context, pid); }
struct variable *sys_fileattr(struct context *context) { struct variable *args = (struct variable*)stack_pop(context->operand_stack); struct variable *path = param_var(args, 1); const char *path2 = byte_array_to_string(path->str); long siz = file_size(path2); long mod = file_timestamp(path2); struct variable *siz2 = variable_new_int(context, (int32_t)siz); struct variable *mod2 = variable_new_int(context, (int32_t)mod); variable_push(context, siz2); variable_push(context, mod2 ); struct variable *result = variable_new_src(context, 2); return result; }
static inline void cfnc_length(struct context *context) { struct variable *args = (struct variable*)stack_pop(context->operand_stack); struct variable *indexable = (struct variable*)array_get(args->list, 0); assert_message(indexable->type==VAR_LST || indexable->type==VAR_STR, "no length for non-indexable"); struct variable *result = variable_new_int(context, indexable->list->length); stack_push(context->operand_stack, result); }
static struct variable *binary_op_int(struct context *context, enum Opcode op, const struct variable *u, const struct variable *v) { int32_t m = u->integer; int32_t n = v->integer; int32_t i; switch (op) { case VM_MUL: i = m * n; break; case VM_DIV: i = m / n; break; case VM_ADD: i = m + n; break; case VM_SUB: i = m - n; break; //case VM_AND: i = m && n; break; case VM_EQU: i = m == n; break; case VM_NEQ: i = m != n; break; //case VM_ORR: i = m || n; break; case VM_GTN: i = m > n; break; case VM_LTN: i = m < n; break; case VM_GRQ: i = m >= n; break; case VM_LEQ: i = m <= n; break; case VM_BND: i = m & n; break; case VM_BOR: i = m | n; break; case VM_MOD: i = m % n; break; case VM_XOR: i = m ^ n; break; case VM_RSF: i = m >> n; break; case VM_LSF: i = m << n; break; default: return (struct variable*)vm_exit_message(context, "bad math int operator"); } return variable_new_int(context, i); }
static void push_int(struct context *context, struct byte_array *program) { null_check(program); int32_t num = serial_decode_int(program); VM_DEBUGPRINT("INT %d\n", num); struct variable* var = variable_new_int(context, num); variable_push(context, var); }
static inline struct variable *cfnc_char(struct context *context) { struct variable *args = (struct variable*)stack_pop(context->operand_stack); struct variable *from = (struct variable*)array_get(args->list.ordered, 0); struct variable *index = (struct variable*)array_get(args->list.ordered, 1); assert_message(from->type == VAR_STR, "char from a non-str"); assert_message(index->type == VAR_INT, "non-int index"); uint8_t n = byte_array_get(from->str, index->integer); return variable_new_int(context, n); }
struct variable *sys_write(struct context *context) { struct variable *args = (struct variable*)stack_pop(context->operand_stack); struct variable *path = param_var(args, 1); struct variable *v = param_var(args, 2); uint32_t from = param_int(args, 3); uint32_t timestamp = param_int(args, 4); int w = write_file(path->str, v->str, from, timestamp); return variable_new_int(context, w); }
struct variable *sys_save(struct context *context) { struct variable *args = (struct variable*)stack_pop(context->operand_stack); struct variable *v = param_var(args, 1); struct variable *path = param_var(args, 2); struct byte_array *bytes = byte_array_new(); variable_serialize(context, bytes, v); int w = write_file(path->str, bytes, 0, -1); byte_array_del(bytes); return variable_new_int(context, w); }
// ascii to integer struct variable *sys_atoi(struct context *context) { struct variable *value = (struct variable*)stack_pop(context->operand_stack); char *str = (char*)((struct variable*)array_get(value->list.ordered, 1))->str->data; uint32_t offset = value->list.ordered->length > 2 ? ((struct variable*)array_get(value->list.ordered, 2))->integer : 0; int n=0, i=0; bool negative = false; if (str[offset] == '-') { negative = true; i++; }; while (isdigit(str[offset+i])) n = n*10 + str[offset + i++] - '0'; n *= negative ? -1 : 1; variable_push(context, variable_new_int(context, n)); variable_push(context, variable_new_int(context, i)); return variable_new_src(context, 2); }
static struct variable *binary_op_float(struct context *context, enum Opcode op, const struct variable *u, const struct variable *v) { float m = u->floater; float n = v->floater; float f = 0; switch (op) { case VM_MUL: f = m * n; break; case VM_DIV: f = m / n; break; case VM_ADD: f = m + n; break; case VM_SUB: f = m - n; break; case VM_NEQ: f = m != n; break; case VM_GTN: return variable_new_int(context, n > m); case VM_LTN: return variable_new_int(context, n < m); case VM_GRQ: return variable_new_int(context, n >= m); case VM_LEQ: return variable_new_int(context, n <= m); default: return (struct variable*)vm_exit_message(context, "bad math float operator"); } return variable_new_float(context, f); }
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; }
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 *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); }
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; }