diff --git a/src/all_types.hpp b/src/all_types.hpp index 01bf264c99..6615afe0f4 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1763,7 +1763,7 @@ struct CodeGen { ZigList timing_events; - Buf *cache_dir; + Buf cache_dir; Buf *out_h_path; ZigList inline_fns; diff --git a/src/buffer.hpp b/src/buffer.hpp index c12d71956f..501e44b5ac 100644 --- a/src/buffer.hpp +++ b/src/buffer.hpp @@ -173,4 +173,9 @@ static inline void buf_upcase(Buf *buf) { } } +static inline Slice buf_to_slice(Buf *buf) { + return Slice{reinterpret_cast(buf_ptr(buf)), buf_len(buf)}; +} + + #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index 5a897517d4..75465fe80b 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -243,7 +243,7 @@ void codegen_set_out_name(CodeGen *g, Buf *out_name) { g->root_out_name = out_name; } -void codegen_set_cache_dir(CodeGen *g, Buf *cache_dir) { +void codegen_set_cache_dir(CodeGen *g, Buf cache_dir) { g->cache_dir = cache_dir; } @@ -5730,7 +5730,7 @@ static LLVMValueRef build_alloca(CodeGen *g, TypeTableEntry *type_entry, const c static void ensure_cache_dir(CodeGen *g) { int err; - if ((err = os_make_path(g->cache_dir))) { + if ((err = os_make_path(&g->cache_dir))) { zig_panic("unable to make cache dir: %s", err_str(err)); } } @@ -6098,7 +6098,7 @@ static void do_code_gen(CodeGen *g) { } Buf *output_path = buf_alloc(); - os_path_join(g->cache_dir, o_basename, output_path); + os_path_join(&g->cache_dir, o_basename, output_path); ensure_cache_dir(g); bool is_small = g->build_mode == BuildModeSmallRelease; @@ -6860,7 +6860,7 @@ static void define_builtin_compile_vars(CodeGen *g) { const char *builtin_zig_basename = "builtin.zig"; Buf *builtin_zig_path = buf_alloc(); - os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path); + os_path_join(&g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path); Buf *contents = codegen_generate_builtin_source(g); ensure_cache_dir(g); @@ -6875,7 +6875,7 @@ static void define_builtin_compile_vars(CodeGen *g) { assert(g->root_package); assert(g->std_package); - g->compile_var_package = new_package(buf_ptr(g->cache_dir), builtin_zig_basename); + g->compile_var_package = new_package(buf_ptr(&g->cache_dir), builtin_zig_basename); g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); g->compile_var_import = add_source_file(g, g->compile_var_package, abs_full_path, contents); diff --git a/src/codegen.hpp b/src/codegen.hpp index b5f3374ec4..6297c4611b 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -47,7 +47,7 @@ void codegen_set_linker_script(CodeGen *g, const char *linker_script); void codegen_set_test_filter(CodeGen *g, Buf *filter); void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix); void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch); -void codegen_set_cache_dir(CodeGen *g, Buf *cache_dir); +void codegen_set_cache_dir(CodeGen *g, Buf cache_dir); void codegen_set_output_h_path(CodeGen *g, Buf *h_path); void codegen_add_time_event(CodeGen *g, const char *name); void codegen_print_timing_report(CodeGen *g, FILE *f); diff --git a/src/ir.cpp b/src/ir.cpp index bcc5d76774..bbce0af225 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17974,8 +17974,11 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr Buf source_dir_path = BUF_INIT; os_path_dirname(import->path, &source_dir_path); - Buf file_path = BUF_INIT; - os_path_resolve(&source_dir_path, rel_file_path, &file_path); + Buf *resolve_paths[] = { + &source_dir_path, + rel_file_path, + }; + Buf file_path = os_path_resolve(resolve_paths, 2); // load from file system into const expr Buf *file_contents = buf_alloc(); diff --git a/src/link.cpp b/src/link.cpp index f65c072bac..f44e8b105e 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -66,7 +66,7 @@ static Buf *build_o_raw(CodeGen *parent_gen, const char *oname, Buf *full_path) const char *o_ext = target_o_file_ext(&child_gen->zig_target); Buf *o_out_name = buf_sprintf("%s%s", oname, o_ext); Buf *output_path = buf_alloc(); - os_path_join(parent_gen->cache_dir, o_out_name, output_path); + os_path_join(&parent_gen->cache_dir, o_out_name, output_path); codegen_link(child_gen, buf_ptr(output_path)); codegen_destroy(child_gen); @@ -587,11 +587,11 @@ static void construct_linker_job_coff(LinkJob *lj) { buf_appendf(def_contents, "\n"); Buf *def_path = buf_alloc(); - os_path_join(g->cache_dir, buf_sprintf("%s.def", buf_ptr(link_lib->name)), def_path); + os_path_join(&g->cache_dir, buf_sprintf("%s.def", buf_ptr(link_lib->name)), def_path); os_write_file(def_path, def_contents); Buf *generated_lib_path = buf_alloc(); - os_path_join(g->cache_dir, buf_sprintf("%s.lib", buf_ptr(link_lib->name)), generated_lib_path); + os_path_join(&g->cache_dir, buf_sprintf("%s.lib", buf_ptr(link_lib->name)), generated_lib_path); gen_lib_args.resize(0); gen_lib_args.append("link"); diff --git a/src/main.cpp b/src/main.cpp index 5f96953f21..4394a1d9ae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -374,25 +374,26 @@ int main(int argc, char **argv) { CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, zig_lib_dir_buf); codegen_set_out_name(g, buf_create_from_str("build")); - Buf build_file_abs = BUF_INIT; - os_path_resolve(buf_create_from_str("."), buf_create_from_str(build_file), &build_file_abs); + Buf *build_file_buf = buf_create_from_str(build_file); + Buf build_file_abs = os_path_resolve(&build_file_buf, 1); Buf build_file_basename = BUF_INIT; Buf build_file_dirname = BUF_INIT; os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename); - Buf *full_cache_dir = buf_alloc(); + Buf full_cache_dir = BUF_INIT; if (cache_dir == nullptr) { - os_path_join(&build_file_dirname, buf_create_from_str(default_zig_cache_name), full_cache_dir); + os_path_join(&build_file_dirname, buf_create_from_str(default_zig_cache_name), &full_cache_dir); } else { - os_path_resolve(buf_create_from_str("."), buf_create_from_str(cache_dir), full_cache_dir); + Buf *cache_dir_buf = buf_create_from_str(cache_dir); + full_cache_dir = os_path_resolve(&cache_dir_buf, 1); } Buf *path_to_build_exe = buf_alloc(); - os_path_join(full_cache_dir, buf_create_from_str("build"), path_to_build_exe); + os_path_join(&full_cache_dir, buf_create_from_str("build"), path_to_build_exe); codegen_set_cache_dir(g, full_cache_dir); args.items[1] = buf_ptr(&build_file_dirname); - args.items[2] = buf_ptr(full_cache_dir); + args.items[2] = buf_ptr(&full_cache_dir); bool build_file_exists; if ((err = os_file_exists(&build_file_abs, &build_file_exists))) { @@ -789,7 +790,7 @@ int main(int argc, char **argv) { Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf; - Buf *full_cache_dir = buf_alloc(); + Buf full_cache_dir = BUF_INIT; Buf *run_exec_path = buf_alloc(); if (cmd == CmdRun) { if (buf_out_name == nullptr) { @@ -799,13 +800,12 @@ int main(int argc, char **argv) { Buf *global_cache_dir = buf_alloc(); os_get_global_cache_directory(global_cache_dir); os_path_join(global_cache_dir, buf_out_name, run_exec_path); - os_path_resolve(buf_create_from_str("."), global_cache_dir, full_cache_dir); + full_cache_dir = os_path_resolve(&global_cache_dir, 1); out_file = buf_ptr(run_exec_path); } else { - os_path_resolve(buf_create_from_str("."), - buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir), - full_cache_dir); + Buf *resolve_paths = buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir); + full_cache_dir = os_path_resolve(&resolve_paths, 1); } Buf *zig_lib_dir_buf = resolve_zig_lib_dir(); @@ -937,7 +937,7 @@ int main(int argc, char **argv) { Buf *test_exe_name = buf_sprintf("test%s", target_exe_file_ext(non_null_target)); Buf *test_exe_path = buf_alloc(); - os_path_join(full_cache_dir, test_exe_name, test_exe_path); + os_path_join(&full_cache_dir, test_exe_name, test_exe_path); for (size_t i = 0; i < test_exec_args.length; i += 1) { if (test_exec_args.items[i] == nullptr) { diff --git a/src/os.cpp b/src/os.cpp index 91a591a7b6..0e62d84a48 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -57,6 +57,54 @@ static clock_serv_t cclock; #include #include +// Ported from std/mem.zig. +// Coordinate struct fields with memSplit function +struct SplitIterator { + size_t index; + Slice buffer; + Slice split_bytes; +}; + +// Ported from std/mem.zig. +static bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte) { + for (size_t i = 0; i < self->split_bytes.len; i += 1) { + if (byte == self->split_bytes.ptr[i]) { + return true; + } + } + return false; +} + +// Ported from std/mem.zig. +static Optional> SplitIterator_next(SplitIterator *self) { + // move to beginning of token + while (self->index < self->buffer.len && + SplitIterator_isSplitByte(self, self->buffer.ptr[self->index])) + { + self->index += 1; + } + size_t start = self->index; + if (start == self->buffer.len) { + return {}; + } + + // move to end of token + while (self->index < self->buffer.len && + !SplitIterator_isSplitByte(self, self->buffer.ptr[self->index])) + { + self->index += 1; + } + size_t end = self->index; + + return Optional>::some(self->buffer.slice(start, end)); +} + +// Ported from std/mem.zig +static SplitIterator memSplit(Slice buffer, Slice split_bytes) { + return SplitIterator{0, buffer, split_bytes}; +} + + #if defined(ZIG_OS_POSIX) static void populate_termination(Termination *term, int status) { if (WIFEXITED(status)) { @@ -266,15 +314,31 @@ int os_path_real(Buf *rel_path, Buf *out_abs_path) { #endif } +#if defined(ZIG_OS_WINDOWS) +// Ported from std/os/path.zig +static bool isAbsoluteWindows(Slice path) { + if (path.ptr[0] == '/') + return true; + + if (path.ptr[0] == '\\') { + return true; + } + if (path.len < 3) { + return false; + } + if (path.ptr[1] == ':') { + if (path.ptr[2] == '/') + return true; + if (path.ptr[2] == '\\') + return true; + } + return false; +} +#endif + bool os_path_is_absolute(Buf *path) { #if defined(ZIG_OS_WINDOWS) - if (buf_starts_with_str(path, "/") || buf_starts_with_str(path, "\\")) - return true; - - if (buf_len(path) >= 3 && buf_ptr(path)[1] == ':') - return true; - - return false; + return isAbsoluteWindows(buf_to_slice(path)); #elif defined(ZIG_OS_POSIX) return buf_ptr(path)[0] == '/'; #else @@ -282,14 +346,423 @@ bool os_path_is_absolute(Buf *path) { #endif } -void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path) { - if (os_path_is_absolute(target_path)) { - buf_init_from_buf(out_abs_path, target_path); - return; +#if defined(ZIG_OS_WINDOWS) + +enum WindowsPathKind { + WindowsPathKindNone, + WindowsPathKindDrive, + WindowsPathKindNetworkShare, +}; + +struct WindowsPath { + Slice disk_designator; + WindowsPathKind kind; + bool is_abs; +}; + + +// Ported from std/os/path.zig +static WindowsPath windowsParsePath(Slice path) { + if (path.len >= 2 && path.ptr[1] == ':') { + return WindowsPath{ + path.slice(0, 2), + WindowsPathKindDrive, + isAbsoluteWindows(path), + }; + } + if (path.len >= 1 && (path.ptr[0] == '/' || path.ptr[0] == '\\') && + (path.len == 1 || (path.ptr[1] != '/' && path.ptr[1] != '\\'))) + { + return WindowsPath{ + path.slice(0, 0), + WindowsPathKindNone, + true, + }; + } + WindowsPath relative_path = { + str(""), + WindowsPathKindNone, + false, + }; + if (path.len < strlen("//a/b")) { + return relative_path; } - os_path_join(ref_path, target_path, out_abs_path); - return; + { + if (memStartsWith(path, str("//"))) { + if (path.ptr[2] == '/') { + return relative_path; + } + + SplitIterator it = memSplit(path, str("/")); + { + Optional> opt_component = SplitIterator_next(&it); + if (!opt_component.is_some) return relative_path; + } + { + Optional> opt_component = SplitIterator_next(&it); + if (!opt_component.is_some) return relative_path; + } + return WindowsPath{ + path.slice(0, it.index), + WindowsPathKindNetworkShare, + isAbsoluteWindows(path), + }; + } + } + { + if (memStartsWith(path, str("\\\\"))) { + if (path.ptr[2] == '\\') { + return relative_path; + } + + SplitIterator it = memSplit(path, str("\\")); + { + Optional> opt_component = SplitIterator_next(&it); + if (!opt_component.is_some) return relative_path; + } + { + Optional> opt_component = SplitIterator_next(&it); + if (!opt_component.is_some) return relative_path; + } + return WindowsPath{ + path.slice(0, it.index), + WindowsPathKindNetworkShare, + isAbsoluteWindows(path), + }; + } + } + return relative_path; +} + +// Ported from std/os/path.zig +static uint8_t asciiUpper(uint8_t byte) { + if (byte >= 'a' && byte <= 'z') { + return 'A' + (byte - 'a'); + } + return byte; +} + +// Ported from std/os/path.zig +static bool asciiEqlIgnoreCase(Slice s1, Slice s2) { + if (s1.len != s2.len) + return false; + for (size_t i = 0; i < s1.len; i += 1) { + if (asciiUpper(s1.ptr[i]) != asciiUpper(s2.ptr[i])) + return false; + } + return true; +} + +// Ported from std/os/path.zig +static bool compareDiskDesignators(WindowsPathKind kind, Slice p1, Slice p2) { + switch (kind) { + case WindowsPathKindNone: + assert(p1.len == 0); + assert(p2.len == 0); + return true; + case WindowsPathKindDrive: + return asciiUpper(p1.ptr[0]) == asciiUpper(p2.ptr[0]); + case WindowsPathKindNetworkShare: + uint8_t sep1 = p1.ptr[0]; + uint8_t sep2 = p2.ptr[0]; + + SplitIterator it1 = memSplit(p1, {&sep1, 1}); + SplitIterator it2 = memSplit(p2, {&sep2, 1}); + + // TODO ASCII is wrong, we actually need full unicode support to compare paths. + return asciiEqlIgnoreCase(SplitIterator_next(&it1).value, SplitIterator_next(&it2).value) && + asciiEqlIgnoreCase(SplitIterator_next(&it1).value, SplitIterator_next(&it2).value); + } + zig_unreachable(); +} + +// Ported from std/os/path.zig +static Buf os_path_resolve_windows(Buf **paths_ptr, size_t paths_len) { + if (paths_len == 0) { + Buf cwd = BUF_INIT; + int err; + if ((err = os_get_cwd(&cwd))) { + zig_panic("get cwd failed"); + } + return cwd; + } + + // determine which disk designator we will result with, if any + char result_drive_buf[2] = {'_', ':'}; + Slice result_disk_designator = str(""); + WindowsPathKind have_drive_kind = WindowsPathKindNone; + bool have_abs_path = false; + size_t first_index = 0; + size_t max_size = 0; + for (size_t i = 0; i < paths_len; i += 1) { + Slice p = buf_to_slice(paths_ptr[i]); + WindowsPath parsed = windowsParsePath(p); + if (parsed.is_abs) { + have_abs_path = true; + first_index = i; + max_size = result_disk_designator.len; + } + switch (parsed.kind) { + case WindowsPathKindDrive: + result_drive_buf[0] = asciiUpper(parsed.disk_designator.ptr[0]); + result_disk_designator = str(result_drive_buf); + have_drive_kind = WindowsPathKindDrive; + break; + case WindowsPathKindNetworkShare: + result_disk_designator = parsed.disk_designator; + have_drive_kind = WindowsPathKindNetworkShare; + break; + case WindowsPathKindNone: + break; + } + max_size += p.len + 1; + } + + // if we will result with a disk designator, loop again to determine + // which is the last time the disk designator is absolutely specified, if any + // and count up the max bytes for paths related to this disk designator + if (have_drive_kind != WindowsPathKindNone) { + have_abs_path = false; + first_index = 0; + max_size = result_disk_designator.len; + bool correct_disk_designator = false; + + for (size_t i = 0; i < paths_len; i += 1) { + Slice p = buf_to_slice(paths_ptr[i]); + WindowsPath parsed = windowsParsePath(p); + if (parsed.kind != WindowsPathKindNone) { + if (parsed.kind == have_drive_kind) { + correct_disk_designator = compareDiskDesignators(have_drive_kind, result_disk_designator, parsed.disk_designator); + } else { + continue; + } + } + if (!correct_disk_designator) { + continue; + } + if (parsed.is_abs) { + first_index = i; + max_size = result_disk_designator.len; + have_abs_path = true; + } + max_size += p.len + 1; + } + } + + // Allocate result and fill in the disk designator, calling getCwd if we have to. + Slice result; + size_t result_index = 0; + + if (have_abs_path) { + switch (have_drive_kind) { + case WindowsPathKindDrive: { + result = Slice::alloc(max_size); + + memCopy(result, result_disk_designator); + result_index += result_disk_designator.len; + break; + } + case WindowsPathKindNetworkShare: { + result = Slice::alloc(max_size); + SplitIterator it = memSplit(buf_to_slice(paths_ptr[first_index]), str("/\\")); + Slice server_name = SplitIterator_next(&it).value; + Slice other_name = SplitIterator_next(&it).value; + + result.ptr[result_index] = '\\'; + result_index += 1; + result.ptr[result_index] = '\\'; + result_index += 1; + memCopy(result.sliceFrom(result_index), server_name); + result_index += server_name.len; + result.ptr[result_index] = '\\'; + result_index += 1; + memCopy(result.sliceFrom(result_index), other_name); + result_index += other_name.len; + + result_disk_designator = result.slice(0, result_index); + break; + } + case WindowsPathKindNone: { + Buf cwd = BUF_INIT; + int err; + if ((err = os_get_cwd(&cwd))) { + zig_panic("get cwd failed"); + } + WindowsPath parsed_cwd = windowsParsePath(buf_to_slice(&cwd)); + result = Slice::alloc(max_size + parsed_cwd.disk_designator.len + 1); + memCopy(result, parsed_cwd.disk_designator); + result_index += parsed_cwd.disk_designator.len; + result_disk_designator = result.slice(0, parsed_cwd.disk_designator.len); + if (parsed_cwd.kind == WindowsPathKindDrive) { + result.ptr[0] = asciiUpper(result.ptr[0]); + } + have_drive_kind = parsed_cwd.kind; + break; + } + } + } else { + // TODO call get cwd for the result_disk_designator instead of the global one + Buf cwd = BUF_INIT; + int err; + if ((err = os_get_cwd(&cwd))) { + zig_panic("get cwd failed"); + } + result = Slice::alloc(max_size + buf_len(&cwd) + 1); + + memCopy(result, buf_to_slice(&cwd)); + result_index += buf_len(&cwd); + WindowsPath parsed_cwd = windowsParsePath(result.slice(0, result_index)); + result_disk_designator = parsed_cwd.disk_designator; + if (parsed_cwd.kind == WindowsPathKindDrive) { + result.ptr[0] = asciiUpper(result.ptr[0]); + } + have_drive_kind = parsed_cwd.kind; + } + + // Now we know the disk designator to use, if any, and what kind it is. And our result + // is big enough to append all the paths to. + bool correct_disk_designator = true; + for (size_t i = 0; i < paths_len; i += 1) { + Slice p = buf_to_slice(paths_ptr[i]); + WindowsPath parsed = windowsParsePath(p); + + if (parsed.kind != WindowsPathKindNone) { + if (parsed.kind == have_drive_kind) { + correct_disk_designator = compareDiskDesignators(have_drive_kind, result_disk_designator, parsed.disk_designator); + } else { + continue; + } + } + if (!correct_disk_designator) { + continue; + } + SplitIterator it = memSplit(p.sliceFrom(parsed.disk_designator.len), str("/\\")); + while (true) { + Optional> opt_component = SplitIterator_next(&it); + if (!opt_component.is_some) break; + Slice component = opt_component.value; + if (memEql(component, str("."))) { + continue; + } else if (memEql(component, str(".."))) { + while (true) { + if (result_index == 0 || result_index == result_disk_designator.len) + break; + result_index -= 1; + if (result.ptr[result_index] == '\\' || result.ptr[result_index] == '/') + break; + } + } else { + result.ptr[result_index] = '\\'; + result_index += 1; + memCopy(result.sliceFrom(result_index), component); + result_index += component.len; + } + } + } + + if (result_index == result_disk_designator.len) { + result.ptr[result_index] = '\\'; + result_index += 1; + } + + Buf return_value = BUF_INIT; + buf_init_from_mem(&return_value, (char *)result.ptr, result_index); + return return_value; +} +#endif + +#if defined(ZIG_OS_POSIX) +// Ported from std/os/path.zig +static Buf os_path_resolve_posix(Buf **paths_ptr, size_t paths_len) { + if (paths_len == 0) { + Buf cwd = BUF_INIT; + int err; + if ((err = os_get_cwd(&cwd))) { + zig_panic("get cwd failed"); + } + return cwd; + } + + size_t first_index = 0; + bool have_abs = false; + size_t max_size = 0; + for (size_t i = 0; i < paths_len; i += 1) { + Buf *p = paths_ptr[i]; + if (os_path_is_absolute(p)) { + first_index = i; + have_abs = true; + max_size = 0; + } + max_size += buf_len(p) + 1; + } + + uint8_t *result_ptr; + size_t result_len; + size_t result_index = 0; + + if (have_abs) { + result_len = max_size; + result_ptr = allocate_nonzero(result_len); + } else { + Buf cwd = BUF_INIT; + int err; + if ((err = os_get_cwd(&cwd))) { + zig_panic("get cwd failed"); + } + result_len = max_size + buf_len(&cwd) + 1; + result_ptr = allocate_nonzero(result_len); + memcpy(result_ptr, buf_ptr(&cwd), buf_len(&cwd)); + result_index += buf_len(&cwd); + } + + for (size_t i = first_index; i < paths_len; i += 1) { + Buf *p = paths_ptr[i]; + SplitIterator it = memSplit(buf_to_slice(p), str("/")); + while (true) { + Optional> opt_component = SplitIterator_next(&it); + if (!opt_component.is_some) break; + Slice component = opt_component.value; + + if (memEql(component, str("."))) { + continue; + } else if (memEql(component, str(".."))) { + while (true) { + if (result_index == 0) + break; + result_index -= 1; + if (result_ptr[result_index] == '/') + break; + } + } else { + result_ptr[result_index] = '/'; + result_index += 1; + memcpy(result_ptr + result_index, component.ptr, component.len); + result_index += component.len; + } + } + } + + if (result_index == 0) { + result_ptr[0] = '/'; + result_index += 1; + } + + Buf return_value = BUF_INIT; + buf_init_from_mem(&return_value, (char *)result_ptr, result_index); + return return_value; +} +#endif + +// Ported from std/os/path.zig +Buf os_path_resolve(Buf **paths_ptr, size_t paths_len) { +#if defined(ZIG_OS_WINDOWS) + return os_path_resolve_windows(paths_ptr, paths_len); +#elif defined(ZIG_OS_POSIX) + return os_path_resolve_posix(paths_ptr, paths_len); +#else +#error "missing os_path_resolve implementation" +#endif } int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) { @@ -558,7 +1031,7 @@ int os_exec_process(const char *exe, ZigList &args, void os_write_file(Buf *full_path, Buf *contents) { FILE *f = fopen(buf_ptr(full_path), "wb"); if (!f) { - zig_panic("open failed"); + zig_panic("os_write_file failed for %s", buf_ptr(full_path)); } size_t amt_written = fwrite(buf_ptr(contents), 1, buf_len(contents), f); if (amt_written != (size_t)buf_len(contents)) @@ -645,21 +1118,19 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) { int os_get_cwd(Buf *out_cwd) { #if defined(ZIG_OS_WINDOWS) - buf_resize(out_cwd, 4096); - if (GetCurrentDirectory(buf_len(out_cwd), buf_ptr(out_cwd)) == 0) { + char buf[4096]; + if (GetCurrentDirectory(4096, buf) == 0) { zig_panic("GetCurrentDirectory failed"); } + buf_init_from_str(out_cwd, buf); return 0; #elif defined(ZIG_OS_POSIX) - int err = ERANGE; - buf_resize(out_cwd, 512); - while (err == ERANGE) { - buf_resize(out_cwd, buf_len(out_cwd) * 2); - err = getcwd(buf_ptr(out_cwd), buf_len(out_cwd)) ? 0 : errno; + char buf[PATH_MAX]; + char *res = getcwd(buf, PATH_MAX); + if (res == nullptr) { + zig_panic("unable to get cwd: %s", strerror(errno)); } - if (err) - zig_panic("unable to get cwd: %s", strerror(err)); - + buf_init_from_str(out_cwd, res); return 0; #else #error "missing os_get_cwd implementation" @@ -898,21 +1369,20 @@ double os_get_time(void) { } int os_make_path(Buf *path) { - Buf *resolved_path = buf_alloc(); - os_path_resolve(buf_create_from_str("."), path, resolved_path); + Buf resolved_path = os_path_resolve(&path, 1); - size_t end_index = buf_len(resolved_path); + size_t end_index = buf_len(&resolved_path); int err; while (true) { - if ((err = os_make_dir(buf_slice(resolved_path, 0, end_index)))) { + if ((err = os_make_dir(buf_slice(&resolved_path, 0, end_index)))) { if (err == ErrorPathAlreadyExists) { - if (end_index == buf_len(resolved_path)) + if (end_index == buf_len(&resolved_path)) return 0; } else if (err == ErrorFileNotFound) { // march end_index backward until next path component while (true) { end_index -= 1; - if (os_is_sep(buf_ptr(resolved_path)[end_index])) + if (os_is_sep(buf_ptr(&resolved_path)[end_index])) break; } continue; @@ -920,12 +1390,12 @@ int os_make_path(Buf *path) { return err; } } - if (end_index == buf_len(resolved_path)) + if (end_index == buf_len(&resolved_path)) return 0; // march end_index forward until next path component while (true) { end_index += 1; - if (end_index == buf_len(resolved_path) || os_is_sep(buf_ptr(resolved_path)[end_index])) + if (end_index == buf_len(&resolved_path) || os_is_sep(buf_ptr(&resolved_path)[end_index])) break; } } diff --git a/src/os.hpp b/src/os.hpp index cfe4e8f3a2..a44fa8160e 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -49,7 +49,7 @@ void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename); void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname); void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path); int os_path_real(Buf *rel_path, Buf *out_abs_path); -void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path); +Buf os_path_resolve(Buf **paths_ptr, size_t paths_len); bool os_path_is_absolute(Buf *path); int os_get_global_cache_directory(Buf *out_tmp_path); diff --git a/src/util.hpp b/src/util.hpp index 41f8feb591..1e02e3043c 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -186,4 +186,72 @@ static inline double zig_f16_to_double(float16_t x) { return z; } +template +struct Optional { + T value; + bool is_some; + + static inline Optional some(T x) { + return {x, true}; + } +}; + +template +struct Slice { + T *ptr; + size_t len; + + inline Slice slice(size_t start, size_t end) { + assert(end <= len); + assert(end >= start); + return { + ptr + start, + end - start, + }; + } + + inline Slice sliceFrom(size_t start) { + assert(start <= len); + return { + ptr + start, + len - start, + }; + } + + static inline Slice alloc(size_t n) { + return {allocate_nonzero(n), n}; + } +}; + +static inline Slice str(const char *literal) { + return {(uint8_t*)(literal), strlen(literal)}; +} + +// Ported from std/mem.zig +template +static inline bool memEql(Slice a, Slice b) { + if (a.len != b.len) + return false; + for (size_t i = 0; i < a.len; i += 1) { + if (a.ptr[i] != b.ptr[i]) + return false; + } + return true; +} + +// Ported from std/mem.zig +template +static inline bool memStartsWith(Slice haystack, Slice needle) { + if (needle.len > haystack.len) + return false; + return memEql(haystack.slice(0, needle.len), needle); +} + +// Ported from std/mem.zig +template +static inline void memCopy(Slice dest, Slice src) { + assert(dest.len >= src.len); + memcpy(dest.ptr, src.ptr, src.len * sizeof(T)); +} + #endif