v.builder, builtin: use ANSI encoding for the .rsp file under Windows; add builtin string_to_ansi_not_null_terminated + tests (#22409)

This commit is contained in:
kbkpbot 2024-10-05 01:29:13 +08:00 committed by GitHub
parent 5a8ba962a8
commit dc6a9583d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 54 additions and 4 deletions

View File

@ -2,6 +2,7 @@ module builtin
import strings
const cp_acp = 0
const cp_utf8 = 65001
// to_wide returns a pointer to an UTF-16 version of the string receiver.
@ -92,3 +93,27 @@ pub fn string_from_wide2(_wstr &u16, len int) string {
return res
}
}
// wide_to_ansi create an ANSI string, given a windows
// style string, encoded in UTF-16.
// It use CP_ACP, which is ANSI code page identifier, as dest encoding.
// NOTE: It return a vstring(encoded in UTF-8) []u8 under Linux.
pub fn wide_to_ansi(_wstr &u16) []u8 {
$if windows {
num_bytes := C.WideCharToMultiByte(cp_acp, 0, _wstr, -1, 0, 0, 0, 0)
if num_bytes != 0 {
mut str_to := []u8{len: num_bytes}
C.WideCharToMultiByte(cp_acp, 0, _wstr, -1, &char(str_to.data), str_to.len,
0, 0)
return str_to
} else {
return []u8{}
}
} $else {
s := unsafe { string_from_wide(_wstr) }
mut str_to := []u8{len: s.len + 1}
unsafe { vmemcpy(str_to.data, s.str, s.len) }
return str_to
}
return []u8{} // TODO: remove this, bug?
}

View File

@ -184,3 +184,13 @@ pub fn utf8_str_visible_length(s string) int {
}
return l
}
// string_to_ansi_not_null_terminated returns an ANSI version of the string `_str`.
// NOTE: This is most useful for converting a vstring to an ANSI string under Windows.
// NOTE: The ANSI string return is not null-terminated, then you can use `os.write_file_array` write an ANSI file.
pub fn string_to_ansi_not_null_terminated(_str string) []u8 {
wstr := _str.to_wide()
mut ansi := wide_to_ansi(wstr)
ansi.pop() // remove tailing zero
return ansi
}

View File

@ -76,3 +76,12 @@ fn test_reverse_cyrillic_with_string_from_wide() {
z := unsafe { string_from_wide(ws) }
assert z == s
}
fn test_wide_to_ansi() {
ws := 'abc'.to_wide()
assert wide_to_ansi(ws) == [u8(97), 98, 99, 0]
}
fn test_string_to_ansi_not_null_terminated() {
assert string_to_ansi_not_null_terminated('abc') == [u8(97), 98, 99]
}

View File

@ -666,8 +666,14 @@ pub fn (mut v Builder) cc() {
response_file_content = str_args.replace('\\', '\\\\')
rspexpr := '@${response_file}'
cmd = '${v.quote_compiler_name(ccompiler)} ${os.quoted_path(rspexpr)}'
os.write_file(response_file, response_file_content) or {
verror('Unable to write to C response file "${response_file}"')
$if windows {
os.write_file_array(response_file, string_to_ansi_not_null_terminated(response_file_content)) or {
verror('Unable to write to C response file "${response_file}"')
}
} $else {
os.write_file(response_file, response_file_content) or {
verror('Unable to write to C response file "${response_file}"')
}
}
}
if !v.ccoptions.debug_mode {

View File

@ -355,9 +355,9 @@ pub fn (mut v Builder) cc_msvc() {
a << env_ldflags
}
v.dump_c_options(a)
args := '\xEF\xBB\xBF' + a.join(' ')
args := a.join(' ')
// write args to a file so that we dont smash createprocess
os.write_file(out_name_cmd_line, args) or {
os.write_file_array(out_name_cmd_line, string_to_ansi_not_null_terminated(args)) or {
verror('Unable to write response file to "${out_name_cmd_line}"')
}
cmd := '"${r.full_cl_exe_path}" "@${out_name_cmd_line}"'