static int run_slash_script(request_rec* r, void* stack_top) { sl_vm_t* vm; slash_context_t ctx; sl_vm_frame_t exit_frame, exception_frame; char* last_slash; SLVAL error; sl_static_init(); vm = sl_init("apache2"); sl_gc_set_stack_top(vm->arena, stack_top); vm->cwd = sl_alloc_buffer(vm->arena, strlen(r->canonical_filename) + 10); strcpy(vm->cwd, r->canonical_filename); last_slash = strrchr(vm->cwd, '/'); if(last_slash) { *last_slash = 0; } SL_TRY(exit_frame, SL_UNWIND_ALL, { SL_TRY(exception_frame, SL_UNWIND_EXCEPTION, { ctx.headers_sent = 0; ctx.vm = vm; ctx.r = r; vm->data = &ctx; setup_request_object(vm, r); setup_response_object(vm); ap_set_content_type(r, "text/html; charset=utf-8"); sl_do_file(vm, r->canonical_filename); }, error, { sl_response_clear(vm); sl_render_error_page(vm, error); });
SLVAL sl_string_url_decode(sl_vm_t* vm, SLVAL self) { sl_string_t* str = sl_get_string(vm, self); size_t out_cap = 32; size_t out_len = 0; uint8_t* out = sl_alloc_buffer(vm->arena, out_cap); size_t str_i; char tmp[3]; for(str_i = 0; str_i < str->buff_len; str_i++) { if(out_len + 8 >= out_cap) { out_cap *= 2; out = sl_realloc(vm->arena, out, out_cap); } if(str->buff[str_i] == '%') { if(str_i + 2 < str->buff_len) { if(is_hex_char(str->buff[str_i + 1]) && is_hex_char(str->buff[str_i + 2])) { tmp[0] = str->buff[str_i + 1]; tmp[1] = str->buff[str_i + 2]; tmp[2] = 0; out[out_len++] = strtol(tmp, NULL, 16); str_i += 2; continue; } } } if(str->buff[str_i] == '+') { out[out_len++] = ' '; continue; } out[out_len++] = str->buff[str_i]; } return sl_make_string(vm, out, out_len); }
char* sl_iconv(sl_vm_t* vm, char* input_string, size_t input_length, char* from_encoding, char* to_encoding, size_t* output_length) { iconv_t cd = iconv_open(to_encoding, from_encoding); if(cd == (iconv_t)(-1)) { sl_throw_message2(vm, vm->lib.EncodingError, "Unknown encoding"); } char* in_buff = input_string; size_t in_bytes_left = input_length; size_t out_bytes_left = in_bytes_left * 4 + 15; size_t out_cap = out_bytes_left; char* out_buff = sl_alloc_buffer(vm->arena, out_cap); char* retn_out_buff = out_buff; while(1) { size_t ret = iconv(cd, &in_buff, &in_bytes_left, &out_buff, &out_bytes_left); if(ret != (size_t)(-1)) { break; } if(errno == E2BIG) { out_bytes_left = input_length; out_cap += input_length; out_buff = sl_realloc(vm->arena, out_buff, out_cap); continue; } if(errno == EILSEQ || errno == EINVAL) { iconv_close(cd); sl_throw_message2(vm, vm->lib.EncodingError, "Invalid encoding in source buffer"); } break; } iconv_close(cd); *output_length = out_cap - out_bytes_left; return retn_out_buff; }
SLVAL sl_string_html_escape(sl_vm_t* vm, SLVAL self) { sl_string_t* str = sl_get_string(vm, self); size_t out_cap = 32; size_t out_len = 0; size_t str_i; uint8_t* out = sl_alloc_buffer(vm->arena, out_cap); for(str_i = 0; str_i < str->buff_len; str_i++) { if(out_len + 8 >= out_cap) { out_cap *= 2; out = sl_realloc(vm->arena, out, out_cap); } if(str->buff[str_i] == '<') { memcpy(out + out_len, "<", 4); out_len += 4; } else if(str->buff[str_i] == '>') { memcpy(out + out_len, ">", 4); out_len += 4; } else if(str->buff[str_i] == '"') { memcpy(out + out_len, """, 6); out_len += 6; } else if(str->buff[str_i] == '\'') { memcpy(out + out_len, "'", 6); out_len += 6; } else if(str->buff[str_i] == '&') { memcpy(out + out_len, "&", 5); out_len += 5; } else { out[out_len++] = str->buff[str_i]; } } return sl_make_string(vm, out, out_len); }
static void init_compile_state(sl_compile_state_t* cs, sl_vm_t* vm, sl_compile_state_t* parent, size_t init_registers) { size_t i; cs->vm = vm; cs->vars = sl_st_init_table(vm, &sl_string_hash_type); cs->parent = parent; cs->section = sl_alloc(vm->arena, sizeof(sl_vm_section_t)); if(parent) { cs->section->filename = parent->section->filename; } cs->section->max_registers = init_registers; cs->section->req_registers = 0; cs->section->arg_registers = 0; cs->section->insns_cap = 16; cs->section->insns_count = 0; cs->section->insns = sl_alloc(vm->arena, sizeof(sl_vm_insn_t) * cs->section->insns_cap); cs->section->line_mappings_cap = 2; cs->section->line_mappings_count = 0; cs->section->line_mappings = sl_alloc_buffer(vm->arena, sizeof(sl_vm_line_mapping_t) * cs->section->line_mappings_cap); cs->section->can_stack_alloc_frame = true; cs->section->has_try_catch = false; cs->section->opt_skip = NULL; cs->registers = sl_alloc(vm->arena, cs->section->max_registers); for(i = 0; i < init_registers; i++) { cs->registers[i] = 1; } cs->next_last_frames = NULL; }
SLVAL sl_make_string(struct sl_vm* vm, uint8_t* buff, size_t buff_len) { uint8_t* our_buff = sl_alloc_buffer(vm->arena, buff_len + 1); memcpy(our_buff, buff, buff_len); return sl_make_string_no_copy(vm, our_buff, buff_len); }
SLVAL sl_string_concat(sl_vm_t* vm, SLVAL self, SLVAL other) { sl_string_t* a = sl_get_string(vm, self); sl_string_t* b = sl_get_string(vm, other); uint8_t* buff = (uint8_t*)sl_alloc_buffer(vm->arena, a->buff_len + b->buff_len); memcpy(buff, a->buff, a->buff_len); memcpy(buff + a->buff_len, b->buff, b->buff_len); return sl_make_string(vm, buff, a->buff_len + b->buff_len); }
sl_token_t sl_make_string_token(sl_lex_state_t* ls, sl_token_type_t type, char* buff, size_t len) { sl_token_t token; size_t cap = len < 4 ? 4 : len; token.type = type; token.as.str.buff = sl_alloc_buffer(ls->vm->arena, cap); token.as.str.len = len; token.as.str.cap = cap; memcpy(token.as.str.buff, buff, len); return token; }
SLVAL sl_string_concat(sl_vm_t* vm, SLVAL self, SLVAL other) { sl_string_t* a = sl_get_string(vm, self); sl_string_t* b = sl_get_string(vm, other); if(strcmp(a->encoding, b->encoding) != 0) { return sl_string_concat(vm, self, sl_string_encode(vm, other, a->encoding)); } uint8_t* buff = (uint8_t*)sl_alloc_buffer(vm->arena, a->buff_len + b->buff_len); memcpy(buff, a->buff, a->buff_len); memcpy(buff + a->buff_len, b->buff, b->buff_len); return sl_make_string(vm, buff, a->buff_len + b->buff_len); }
char* sl_realpath(sl_vm_t* vm, char* path) { char *cpath, *gcbuff; if(path[0] != '/') { gcbuff = sl_alloc_buffer(vm->arena, strlen(vm->cwd) + strlen(path) + 10); strcpy(gcbuff, vm->cwd); strcat(gcbuff, "/"); strcat(gcbuff, path); path = gcbuff; } #ifdef PATH_MAX cpath = sl_alloc_buffer(vm->arena, PATH_MAX + 1); (void)realpath(path, cpath); return cpath; #else cpath = realpath(path, NULL); gcbuff = sl_alloc_buffer(vm->arena, strlen(cpath) + 1); strcpy(gcbuff, cpath); return gcbuff; #endif }
static SLVAL sl_json_dump(sl_vm_t* vm, SLVAL self, SLVAL object) { json_dump_t dump; dump.vm = vm; dump.buffer_len = 0; dump.buffer_cap = 32; dump.buffer = sl_alloc_buffer(vm->arena, dump.buffer_cap); dump.seen_len = 0; dump.seen_cap = 32; dump.seen_ptrs = sl_alloc(vm->arena, sizeof(void*) * dump.seen_cap); json_dump(&dump, object); return sl_make_string(vm, dump.buffer, dump.buffer_len); (void)self; }
char* sl_realpath(sl_vm_t* vm, char* path) { char *cpath, *gcbuff; if(!path[0] || path[1] != ':') { gcbuff = sl_alloc_buffer(vm->arena, strlen(vm->cwd) + strlen(path) + 10); strcpy(gcbuff, vm->cwd); strcat(gcbuff, "/"); strcat(gcbuff, path); path = gcbuff; } #ifdef _MAX_PATH cpath = sl_alloc_buffer(vm->arena, _MAX_PATH + 1); cpath = _fullpath(cpath, path, _MAX_PATH); return cpath; #else cpath = _fullpath(NULL, path, 0); gcbuff = sl_alloc_buffer(vm->arena, strlen(cpath) + 1); strcpy(gcbuff, cpath); free(cpath); return gcbuff; #endif }
SLVAL sl_string_url_encode(sl_vm_t* vm, SLVAL self) { sl_string_t* str = sl_get_string(vm, self); size_t out_cap = 32; size_t out_len = 0; uint8_t* out = sl_alloc_buffer(vm->arena, out_cap); size_t clen = str->buff_len; uint8_t* cbuff = str->buff; uint32_t c; uint8_t utf8buff[8]; uint32_t utf8len; while(clen) { if(out_len + 16 >= out_cap) { out_cap *= 2; out = sl_realloc(vm->arena, out, out_cap); } c = sl_utf8_each_char(vm, &cbuff, &clen); if(c >= 'A' && c <= 'Z') { out[out_len++] = c; continue; } if(c >= 'a' && c <= 'z') { out[out_len++] = c; continue; } if(c >= '0' && c <= '9') { out[out_len++] = c; continue; } if(c == '-' || c == '_' || c == '.' || c == '~') { out[out_len++] = c; continue; } if(c == ' ') { out[out_len++] = '+'; continue; } utf8len = sl_utf32_char_to_utf8(vm, c, utf8buff); for(unsigned int i = 0; i < utf8len; i++) { sprintf((char*)out + out_len, "%%%2X", utf8buff[i]); out_len += 3; } } return sl_make_string(vm, out, out_len); }
SLVAL sl_string_inspect(sl_vm_t* vm, SLVAL self) { sl_string_t* str = sl_get_string(vm, self); size_t out_cap = 32; size_t out_len = 0; size_t str_i; uint8_t* out = sl_alloc_buffer(vm->arena, out_cap); out[out_len++] = '"'; for(str_i = 0; str_i < str->buff_len; str_i++) { if(out_len + 8 >= out_cap) { out_cap *= 2; out = sl_realloc(vm->arena, out, out_cap); } if(str->buff[str_i] == '"') { memcpy(out + out_len, "\\\"", 2); out_len += 2; } else if(str->buff[str_i] == '\\') { memcpy(out + out_len, "\\\\", 2); out_len += 2; } else if(str->buff[str_i] == '\n') { memcpy(out + out_len, "\\n", 2); out_len += 2; } else if(str->buff[str_i] == '\r') { memcpy(out + out_len, "\\r", 2); out_len += 2; } else if(str->buff[str_i] == '\t') { memcpy(out + out_len, "\\t", 2); out_len += 2; } else if(str->buff[str_i] < 0x20) { out[out_len++] = '\\'; out[out_len++] = 'x'; out[out_len++] = '0' + str->buff[str_i] / 0x10; if(str->buff[str_i] % 0x10 < 10) { out[out_len++] = '0' + str->buff[str_i] % 0x10; } else { out[out_len++] = 'A' + (str->buff[str_i] % 0x10) - 10; } } else { out[out_len++] = str->buff[str_i]; } } out[out_len++] = '"'; return sl_make_string(vm, out, out_len); }
static SLVAL vm_helper_build_string(sl_vm_t* vm, SLVAL* vals, size_t count) { for(size_t i = 0; i < count; i++) { vals[i] = sl_to_s(vm, vals[i]); } size_t len = 0; for(size_t i = 0; i < count; i++) { len += ((sl_string_t*)sl_get_ptr(vals[i]))->buff_len; } uint8_t* buff = sl_alloc_buffer(vm->arena, len + 1); size_t j = 0; for(size_t i = 0; i < count; i++) { sl_string_t* str = (void*)sl_get_ptr(vals[i]); memcpy(buff + j, str->buff, str->buff_len); j += str->buff_len; } return sl_make_string_no_copy(vm, buff, len); }
SLVAL sl_make_string(sl_vm_t* vm, uint8_t* buff, size_t buff_len) { SLVAL vstr = sl_allocate(vm, vm->lib.String); sl_string_t* str = (sl_string_t*)sl_get_ptr(vstr); if(sl_is_valid_utf8(buff, buff_len)) { str->encoding = "UTF-8"; str->char_len = sl_utf8_strlen(vm, buff, buff_len); } else { str->encoding = "CP1252"; str->char_len = buff_len; } str->buff = sl_alloc_buffer(vm->arena, buff_len + 1); memcpy(str->buff, buff, buff_len); str->buff[buff_len] = 0; str->buff_len = buff_len; str->hash_set = 0; return vstr; }
int main(int argc, char** argv) { sl_static_init(); sl_vm_t* vm = sl_init("disasm"); if(argc < 1) { fprintf(stderr, "Usage: slash-dis <source file>\n"); exit(1); } FILE* f = fopen(argv[1], "r"); if(!f) { fprintf(stderr, "Could not open %s for reading.\n", argv[1]); exit(1); } fseek(f, 0, SEEK_END); size_t size = ftell(f); fseek(f, 0, SEEK_SET); char* source = sl_alloc_buffer(vm->arena, size + 1); fread(source, size, 1, f); fclose(f); SLVAL err; sl_vm_frame_t frame; SL_TRY(frame, SL_UNWIND_ALL, { size_t token_count; sl_token_t* tokens = sl_lex(vm, (uint8_t*)argv[1], (uint8_t*)source, size, &token_count, 0); sl_node_base_t* ast = sl_parse(vm, tokens, token_count, (uint8_t*)argv[1]); sl_vm_section_t* section = sl_compile(vm, ast, (uint8_t*)argv[1]); disassemble(vm, section); while(section_j < section_i) { disassemble(vm, section_queue[++section_j]); } }, err, {
SLVAL sl_response_flush(sl_vm_t* vm) { sl_response_internal_opts_t* resp = response(vm); size_t i, total_size = 0, offset = 0; char* output_buffer; sl_string_t* str; for(i = 0; i < resp->output_len; i++) { str = (sl_string_t*)sl_get_ptr(resp->output[i]); total_size += str->buff_len; } output_buffer = sl_alloc_buffer(vm->arena, total_size + 1); for(i = 0; i < resp->output_len; i++) { str = (sl_string_t*)sl_get_ptr(resp->output[i]); memcpy(output_buffer + offset, str->buff, str->buff_len); offset += str->buff_len; } resp->write(vm, output_buffer, total_size); resp->output_len = 0; return vm->lib.nil; }
SLVAL sl_string_lower(sl_vm_t* vm, SLVAL selfv) { sl_string_t* self = sl_get_string(vm, selfv); sl_string_t* retn = sl_get_string(vm, sl_allocate(vm, vm->lib.String)); memcpy(retn, self, sizeof(sl_string_t)); retn->buff = sl_alloc_buffer(vm->arena, retn->buff_len); size_t len = self->buff_len; uint8_t* buff = self->buff; size_t out_offset = 0; uint32_t lower_c; while(len) { uint32_t c = sl_utf8_each_char(vm, &buff, &len); lower_c = sl_unicode_tolower(c); out_offset += sl_utf32_char_to_utf8(vm, lower_c, retn->buff + out_offset); } return sl_make_ptr((sl_object_t*)retn); }
static void sl_setup_regexp(sl_vm_t* vm, sl_regexp_t* re_ptr, uint8_t* re_buff, size_t re_len, uint8_t* opts_buff, size_t opts_len) { char buff[256]; const char* error; char* rez; int error_offset; int opts = DEFAULT_OPTIONS; pcre* re; size_t i; for(i = 0; i < opts_len; i++) { switch(opts_buff[i]) { case 'i': opts |= PCRE_CASELESS; break; case 'x': opts |= PCRE_EXTENDED; break; default: sprintf(buff, "Unknown regular expression option '%c'", opts_buff[i]); sl_throw_message2(vm, vm->lib.ArgumentError, buff); } } if(memchr(re_buff, 0, re_len)) { sl_throw_message2(vm, vm->lib.ArgumentError, "Regular expression contains null byte"); } rez = sl_alloc_buffer(vm->arena, re_len + 1); memcpy(rez, re_buff, re_len); rez[re_len] = 0; re = pcre_compile(rez, opts, &error, &error_offset, NULL); if(!re) { sl_throw_message2(vm, vm->lib.SyntaxError, (char*)error); } re_ptr->source = sl_make_string(vm, re_buff, re_len); re_ptr->options = opts; re_ptr->re = re; re_ptr->study = NULL; }
static SLVAL sl_mysql_stmt_execute(sl_vm_t* vm, SLVAL self, size_t argc, SLVAL* argv) { mysql_stmt_t* stmt = get_mysql_stmt(vm, self); size_t req = mysql_stmt_param_count(stmt->stmt); if(argc < req) { char buff[100]; sprintf(buff, "Prepared statement has %lu parameter markers, but only %lu parameters were given", req, argc); sl_throw_message2(vm, vm->lib.ArgumentError, buff); } if(!stmt->bind) { stmt->bind = sl_alloc(vm->arena, sizeof(MYSQL_BIND) * req); } for(size_t i = 0; i < req; i++) { stmt->bind[i].buffer_type = MYSQL_TYPE_STRING; sl_string_t* str = sl_get_string(vm, sl_to_s(vm, argv[i])); stmt->bind[i].buffer = str->buff; stmt->bind[i].buffer_length = str->buff_len; stmt->bind[i].length = NULL; stmt->bind[i].is_null = NULL; stmt->bind[i].is_unsigned = 1; stmt->bind[i].error = NULL; } if(mysql_stmt_bind_param(stmt->stmt, stmt->bind)) { sl_mysql_stmt_check_error(vm, stmt->stmt); } if(mysql_stmt_execute(stmt->stmt)) { sl_mysql_stmt_check_error(vm, stmt->stmt); } MYSQL_RES* res = mysql_stmt_result_metadata(stmt->stmt); if(!res) { /* query did not produce a result set */ return sl_make_int(vm, mysql_stmt_affected_rows(stmt->stmt)); } int field_count = mysql_stmt_field_count(stmt->stmt); MYSQL_FIELD* field; SLVAL field_names[field_count]; enum enum_field_types field_types[field_count]; size_t field_i = 0; while((field = mysql_fetch_field(res))) { field_names[field_i] = sl_make_cstring(vm, field->name); if(field->type == MYSQL_TYPE_LONG || field->type == MYSQL_TYPE_SHORT || field->type == MYSQL_TYPE_TINY) { field_types[field_i] = MYSQL_TYPE_LONG; } else { field_types[field_i] = MYSQL_TYPE_STRING; } field_i++; } MYSQL_BIND output_binds[field_count]; my_bool output_errors[field_count]; my_bool output_is_nulls[field_count]; unsigned long output_lengths[field_count]; for(int i = 0; i < field_count; i++) { output_binds[i].buffer_type = MYSQL_TYPE_STRING; output_binds[i].buffer = NULL; output_binds[i].buffer_length = 0; output_binds[i].length = &output_lengths[i]; output_binds[i].is_null = &output_is_nulls[i]; output_binds[i].error = &output_errors[i]; } if(mysql_stmt_bind_result(stmt->stmt, output_binds)) { sl_mysql_stmt_check_error(vm, stmt->stmt); } SLVAL result_rows = sl_make_array(vm, 0, NULL); while(1) { int code = mysql_stmt_fetch(stmt->stmt); if(code == MYSQL_NO_DATA) { break; } if(code == 1) { sl_mysql_stmt_check_error(vm, stmt->stmt); } SLVAL row = sl_make_dict(vm, 0, NULL); for(int i = 0; i < field_count; i++) { MYSQL_BIND cell; cell.length = &output_lengths[i]; cell.is_null = &output_is_nulls[i]; cell.error = &output_errors[i]; cell.buffer_type = field_types[i]; int buffer_long; switch(field_types[i]) { case MYSQL_TYPE_LONG: cell.buffer = &buffer_long; cell.buffer_length = sizeof(buffer_long); break; default: /* MYSQL_TYPE_STRING */ cell.buffer = sl_alloc_buffer(vm->arena, output_lengths[i] + 1); cell.buffer_length = output_lengths[i]; break; } if(mysql_stmt_fetch_column(stmt->stmt, &cell, i, 0)) { sl_mysql_stmt_check_error(vm, stmt->stmt); } switch(field_types[i]) { case MYSQL_TYPE_LONG: sl_dict_set(vm, row, field_names[i], sl_make_int(vm, buffer_long)); break; default: /* MYSQL_TYPE_STRING */ sl_dict_set(vm, row, field_names[i], sl_make_string(vm, cell.buffer, output_lengths[i])); break; } } sl_array_push(vm, result_rows, 1, &row); } return result_rows; }