#define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include #include struct b_path { struct b_dsref base; struct b_string *pathstr; }; static void path_release(struct b_dsref *obj); static void path_to_string(struct b_dsref *obj, struct b_stringstream *out); static struct b_dsref_type path_type = { .t_name = "corelib::path", .t_flags = B_DSREF_FUNDAMENTAL, .t_id = B_DSREF_TYPE_PATH, .t_instance_size = sizeof(struct b_path), .t_release = path_release, .t_to_string = path_to_string, }; struct b_path *b_path_create() { struct b_path *path = (struct b_path *)b_dsref_type_instantiate(&path_type); if (!path) { return NULL; } path->pathstr = b_string_create(); if (!path->pathstr) { b_path_release(path); return NULL; } return path; } struct b_path *b_path_create_root() { const char *system_drive = getenv("SystemDrive"); if (!system_drive) { /* take an educated guess. */ system_drive = "C:"; } size_t system_drive_len = strlen(system_drive); struct b_path *path = b_path_create(); if (!path) { return NULL; } b_string_append_cstr(path->pathstr, system_drive); if (system_drive[system_drive_len - 1] != '\\') { b_string_append_cstr(path->pathstr, "\\"); } return path; } struct b_path *b_path_create_cwd() { DWORD cwd_len = GetCurrentDirectory(0, NULL); if (cwd_len == 0) { return NULL; } TCHAR *cwd_buf = malloc(cwd_len + 1); if (!cwd_buf) { return NULL; } cwd_len = GetCurrentDirectory(cwd_len + 1, cwd_buf); if (cwd_len == 0) { free(cwd_buf); return NULL; } struct b_path *path = b_path_create(); if (!path) { return NULL; } for (DWORD i = 0; i < cwd_len; i++) { TCHAR c = cwd_buf[i]; char s[] = {(c >= 128 ? '?' : (char)c), 0}; b_string_append_cstr(path->pathstr, s); } free(cwd_buf); return path; } struct b_path *b_path_create_from_cstr(const char *cstr) { struct b_path *path = b_path_create(); if (!path) { return NULL; } char prev = 0; for (size_t i = 0; cstr[i]; i++) { char c = cstr[i]; if (c == '\\') { c = '/'; } if (prev == '/' && c == '/') { continue; } char s[] = {c, 0}; b_string_append_cstr(path->pathstr, s); prev = c; } while (b_string_back(path->pathstr) == '/') { b_string_pop_back(path->pathstr); } return path; } static void append_path(struct b_path *dest, const struct b_path *src) { if (b_path_is_absolute(src)) { b_string_clear(dest->pathstr); b_string_append_s(dest->pathstr, src->pathstr); return; } if (b_string_back(dest->pathstr) != '/' && b_string_front(src->pathstr) != '/') { char s[] = {'/', 0}; b_string_append_cstr(dest->pathstr, s); } b_string_append_s(dest->pathstr, src->pathstr); } struct b_path *b_path_join( const b_path *paths[], size_t nr_paths) { struct b_path *result = b_path_create(); if (!result) { return NULL; } for (size_t i = 0; i < nr_paths; i++) { if (paths[i]) { append_path(result, paths[i]); } } return result; } struct b_path *b_path_make_absolute(const struct b_path *in) { return NULL; } struct b_path *b_path_make_relative(const struct b_path *in) { return NULL; } struct b_path *b_path_make_canonical(const struct b_path *in) { return NULL; } bool b_path_is_absolute(const struct b_path *path) { const char *s = b_string_ptr(path->pathstr); size_t i; for (i = 0; s[i]; i++) { char c = s[i]; if (!isalpha(c)) { break; } } if (s[i++] != ':') { return false; } if (s[i++] != '/') { return false; } return true; } bool b_path_exists(const struct b_path *path) { DWORD attrib = GetFileAttributesA(b_path_ptr(path)); return attrib != INVALID_FILE_ATTRIBUTES; } bool b_path_is_file(const struct b_path *path) { DWORD attrib = GetFileAttributesA(b_path_ptr(path)); if (attrib == INVALID_FILE_ATTRIBUTES) { return false; } return (attrib & FILE_ATTRIBUTE_NORMAL) != 0; } bool b_path_is_directory(const struct b_path *path) { DWORD attrib = GetFileAttributesA(b_path_ptr(path)); if (attrib == INVALID_FILE_ATTRIBUTES) { return false; } return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; } const char *b_path_ptr(const struct b_path *path) { return b_string_ptr(path->pathstr); } void path_release(struct b_dsref* obj) { struct b_path *path = B_PATH(obj); b_string_release(path->pathstr); } void path_to_string(struct b_dsref* obj, struct b_stringstream* out) { struct b_path *path = (struct b_path *)obj; b_stringstream_add(out, b_string_ptr(path->pathstr)); }