diff --git a/src/compiler/linker.c b/src/compiler/linker.c index 40bdc13fd..78aef9a6b 100644 --- a/src/compiler/linker.c +++ b/src/compiler/linker.c @@ -778,9 +778,7 @@ static char *assemble_linker_command(const char **args, bool extra_quote) assert(arg != scratch_buffer.str && "Incorrectly passed a scratch buffer string as an argument."); if (arg == quote_arg) { - scratch_buffer_append_char('"'); - scratch_buffer_append_in_quote(args[++i]); - scratch_buffer_append_char('"'); + scratch_buffer_append_cmd_argument(args[++i]); continue; } if (arg == concat_arg) @@ -791,25 +789,15 @@ static char *assemble_linker_command(const char **args, bool extra_quote) } if (arg == concat_file_arg) { - scratch_buffer_append_char('"'); const char *a = args[++i]; - scratch_buffer_append_in_quote(a); - size_t len = strlen(a); - char c = len ? a[len - 1] : '/'; - if (c != '/' && !(PLATFORM_WINDOWS && c == '\\')) - { - scratch_buffer_append(PLATFORM_WINDOWS ? "\\\\" : "/"); - } - scratch_buffer_append_in_quote(args[++i]); - scratch_buffer_append_char('"'); + const char *path = file_append_path_temp(a, args[++i]); + scratch_buffer_append_cmd_argument(path); continue; } if (arg == concat_quote_arg) { scratch_buffer_append(args[++i]); - scratch_buffer_append_char('"'); - scratch_buffer_append_in_quote(args[++i]); - scratch_buffer_append_char('"'); + scratch_buffer_append_cmd_argument(args[++i]); continue; } scratch_buffer_append(arg); diff --git a/src/utils/file_utils.c b/src/utils/file_utils.c index 1a3f506cc..e5ef889f1 100644 --- a/src/utils/file_utils.c +++ b/src/utils/file_utils.c @@ -480,6 +480,31 @@ bool file_exists(const char *path) return S_ISDIR(st.st_mode) || S_ISREG(st.st_mode) || S_ISREG(st.st_mode); } +#define PATH_BUFFER_SIZE 16384 +static char path_buffer[PATH_BUFFER_SIZE]; + +const char *file_append_path_temp(const char *path, const char *name) +{ + size_t path_len = strlen(path); + if (!path_len) return name; + size_t name_len = strlen(name); + if (path_len + name_len + 1 >= PATH_BUFFER_SIZE) error_exit("Error generating path from %s and %s: buffer max size exceeded.", path, name); +#if PLATFORM_WINDOWS + if (path[path_len - 1] == '\\') goto CONCAT; + if (path[path_len - 1] == '/') goto CONCAT; + sprintf(path_buffer, "%s\\%s", path, name); + path_buffer[name_len + path_len + 1] = 0; + return path_buffer; +#else + if (path[path_len - 1] == '/') goto CONCAT; + sprintf(path_buffer, "%s/%s", path, name); + path_buffer[name_len + path_len + 1] = 0; +#endif +CONCAT: + sprintf(path_buffer, "%s%s", path, name); + path_buffer[name_len + path_len] = 0; + return path_buffer; +} const char *file_append_path(const char *path, const char *name) { size_t path_len = strlen(path); diff --git a/src/utils/lib.h b/src/utils/lib.h index 10ed52007..76d26545b 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -88,6 +88,7 @@ void file_find_top_dir(); bool file_has_suffix_in_list(const char *file_name, int name_len, const char **suffix_list, int suffix_count); void file_add_wildcard_files(const char ***files, const char *path, bool recursive, const char **suffix_list, int suffix_count); const char *file_append_path(const char *path, const char *name); +const char *file_append_path_temp(const char *path, const char *name); const char *execute_cmd(const char *cmd, bool ignore_failure, const char *stdin_string); @@ -162,6 +163,8 @@ void scratch_buffer_append_in_quote(const char *string); void scratch_buffer_append_char_repeat(char c, size_t count); void scratch_buffer_append_signed_int(int64_t i); void scratch_buffer_append_double(double d); +void scratch_buffer_append_shell_escaped(const char *string); +void scratch_buffer_append_cmd_argument(const char *string); UNUSED void scratch_buffer_append_unsigned_int(uint64_t i); void scratch_buffer_printf(const char *format, ...); char *scratch_buffer_to_string(void); diff --git a/src/utils/stringutils.c b/src/utils/stringutils.c index 1873adfc1..7586ed48b 100644 --- a/src/utils/stringutils.c +++ b/src/utils/stringutils.c @@ -286,6 +286,7 @@ void str_trim_end(char *str) } } } + char *str_cat(const char *a, const char *b) { unsigned a_len = (unsigned)strlen(a); @@ -320,6 +321,38 @@ void scratch_buffer_append_len(const char *string, size_t len) scratch_buffer.len += (uint32_t)len; } +static void scratch_buffer_append_double_quoted(const char *string) +{ + scratch_buffer_append_char('"'); + size_t len = strlen(string); + for (size_t i = 0; i < len; ) + { + char c = string[i++]; + switch (c) + { + case '"': + scratch_buffer_append("\\\""); + continue; + case '\\': + { + int backslash_count = 1; + for (; i < len && string[i] == '\\'; i++, backslash_count++) {} + if (i == len || string[i] == '"') + { + scratch_buffer_append_char_repeat('\\', backslash_count * 2); + } + else + { + scratch_buffer_append_char_repeat('\\', backslash_count); + } + continue; + } + } + scratch_buffer_append_char(c); + } + scratch_buffer_append_char('"'); +} + #if PLATFORM_WINDOWS static bool contains_whitespace_or_quotes(const char *string) { @@ -340,6 +373,49 @@ static bool contains_whitespace_or_quotes(const char *string) } #endif +void scratch_buffer_append_cmd_argument(const char *string) +{ +#if PLATFORM_WINDOWS + if (contains_whitespace_or_quotes(string)) + { + scratch_buffer_append_double_quoted(string); + } + else + { + scratch_buffer_append(string); + } +#else + scratch_buffer_append_shell_escaped(string); +#endif +} + + +void scratch_buffer_append_shell_escaped(const char *string) +{ + char c; + while ((c = string++[0]) != '\0') + { + if ((unsigned)c < 0x80) + { + switch (c) + { + case LOWER_CHAR_CASE: + case UPPER_CHAR_CASE: + case NUMBER_CHAR_CASE: + case '_': + case '/': + case '.': + case ',': + case '-': + break; + default: + scratch_buffer_append_char('\\'); + break; + } + } + scratch_buffer_append_char(c); + } +} void scratch_buffer_append(const char *string) { scratch_buffer_append_len(string, strlen(string));