From 79bf40f909cefdc611bfa13f70ae55b52ac41d23 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sun, 10 Mar 2019 16:52:53 +0100 Subject: Load @import files relative to the file that uses @import --- src/parser.c | 36 ++++++++++++++++++++++++------------ src/std/file.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/parser.c b/src/parser.c index 22c8b77..f531705 100644 --- a/src/parser.c +++ b/src/parser.c @@ -478,24 +478,27 @@ int parser_parse_file(Parser *self, BufferView filepath) { int result; char *file_data; usize file_size; - char *filepath_tmp; amal_log_debug("Parsing %.*s", (int)filepath.size, filepath.data); assert(!self->started && "Parser can't be reused. Create a new parser."); self->started = bool_true; - /* TODO: Somehow free this... */ - /*return_if_error(scoped_allocator_alloc(self->allocator, filepath.size + 1, (void**)&filepath_tmp));*/ - filepath_tmp = malloc(filepath.size + 1); - am_memcpy(filepath_tmp, filepath.data, filepath.size); - filepath_tmp[filepath.size] = '\0'; - result = read_whole_file(filepath_tmp, &file_data, &file_size); + assert(filepath.size > 0 && filepath.data[filepath.size] == '\0'); + result = read_whole_file(filepath.data, &file_data, &file_size); if(result != 0) return result; - result = parser_parse_buffer(self, create_buffer_view(file_data, file_size), create_buffer_view(filepath_tmp, filepath.size)); - /* TODO: Somehow free this.. causes issue where filepath becomes corrupt */ - /*am_free(file_data);*/ + result = parser_parse_buffer(self, create_buffer_view(file_data, file_size), filepath); return result; } +static CHECK_RESULT int file_path_join(BufferView directory, BufferView file, ScopedAllocator *allocator, Buffer *result) { + return_if_error(buffer_init(result, allocator)); + return_if_error(buffer_append(result, NULL, directory.size + 1 + file.size + 1)); + am_memcpy(result->data, directory.data, directory.size); + result->data[directory.size] = '/'; + am_memcpy(result->data + directory.size + 1, file.data, file.size); + result->data[directory.size + 1 + file.size] = '\0'; + return 0; +} + /* Path can be path to included library path (or system library path) in which case the path separator is a dot, otherwise the path separator is forward slash '/' @@ -503,7 +506,16 @@ the path separator is a dot, otherwise the path separator is forward slash '/' int parser_queue_file(Parser *self, BufferView path) { /* TODO: Do not load same path twice or the compile will fail (and it can have recursive import) also for performance reasons */ /* TODO: Parse special path (to include library path with dots) */ - /* TODO: Path should be relative to the file that uses @import */ - throw_if_error(amal_compiler_load_file(self->compiler, path)); + BufferView file_directory; + BufferView filename; + Buffer file_to_parse; + file_directory = file_get_parent_directory(self->tokenizer.code_name); + filename = file_get_name(path); + return_if_error(file_path_join(file_directory, filename, self->allocator, &file_to_parse)); + /* + We want buffer to be null terminated but null terminated character + should not be included for the length. + */ + throw_if_error(amal_compiler_load_file(self->compiler, create_buffer_view(file_to_parse.data, file_to_parse.size - 1))); return PARSER_OK; } diff --git a/src/std/file.c b/src/std/file.c index 46099b4..098b18f 100644 --- a/src/std/file.c +++ b/src/std/file.c @@ -14,6 +14,7 @@ #include #define SCANDIR_PATH_LENGTH 4096 +#define MAX_FILE_SIZE 1024*1024*48 /* 48 mb */ static int scan_dir_recursive_internal(char *dir_path, int path_length, scan_dir_callback_func callback_func, void *userdata) { DIR *dir; @@ -165,11 +166,40 @@ int mapped_file_deinit(MappedFile *self) { return 0; } +typedef enum { + REGULAR, + DIRECTORY, + OTHER +} FileType; + +static CHECK_RESULT int file_get_type(const char *filepath, FileType *type) { + struct stat file_stats; + if(stat(filepath, &file_stats) == -1) { + amal_log_perror(filepath); + return -1; + } + + if(file_stats.st_mode & S_IFDIR) + *type = DIRECTORY; + else if(file_stats.st_mode & S_IFREG) + *type = REGULAR; + else + *type = OTHER; + return 0; +} + int read_whole_file(const char *filepath, char **data, usize *size) { + FileType file_type; FILE *file; int result; usize bytes_read; + return_if_error(file_get_type(filepath, &file_type)); + if(file_type != REGULAR) { + amal_log_error("Expected file %s to be a regular file", filepath); + return -2; + } + result = 0; file = fopen(filepath, "rb"); if(!file) { @@ -192,6 +222,12 @@ int read_whole_file(const char *filepath, char **data, usize *size) { goto cleanup; } + if(*size > MAX_FILE_SIZE) { + amal_log_error("File %s is too large (larger than 48 megabytes)", filepath); + result = -1; + goto cleanup; + } + cleanup_if_error(am_malloc(*size, (void**)data)); bytes_read = fread(*data, 1, *size, file); if(bytes_read != *size) { @@ -202,3 +238,21 @@ int read_whole_file(const char *filepath, char **data, usize *size) { fclose(file); return result; } + +BufferView file_get_parent_directory(BufferView filepath) { + int i; + for(i = filepath.size - 1; i >= 0; --i) { + if(filepath.data[i] == '/') + return create_buffer_view(filepath.data, i); + } + return create_buffer_view(filepath.data, 0); +} + +BufferView file_get_name(BufferView filepath) { + int i; + for(i = filepath.size - 1; i >= 0; --i) { + if(filepath.data[i] == '/') + return create_buffer_view(filepath.data + i, filepath.size - i); + } + return filepath; +} -- cgit v1.2.3