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 import strings
const cp_acp = 0
const cp_utf8 = 65001 const cp_utf8 = 65001
// to_wide returns a pointer to an UTF-16 version of the string receiver. // 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 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 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) } z := unsafe { string_from_wide(ws) }
assert z == s 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,10 +666,16 @@ pub fn (mut v Builder) cc() {
response_file_content = str_args.replace('\\', '\\\\') response_file_content = str_args.replace('\\', '\\\\')
rspexpr := '@${response_file}' rspexpr := '@${response_file}'
cmd = '${v.quote_compiler_name(ccompiler)} ${os.quoted_path(rspexpr)}' cmd = '${v.quote_compiler_name(ccompiler)} ${os.quoted_path(rspexpr)}'
$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 { os.write_file(response_file, response_file_content) or {
verror('Unable to write to C response file "${response_file}"') verror('Unable to write to C response file "${response_file}"')
} }
} }
}
if !v.ccoptions.debug_mode { if !v.ccoptions.debug_mode {
v.pref.cleanup_files << v.out_name_c v.pref.cleanup_files << v.out_name_c
if !v.pref.no_rsp { if !v.pref.no_rsp {

View File

@ -355,9 +355,9 @@ pub fn (mut v Builder) cc_msvc() {
a << env_ldflags a << env_ldflags
} }
v.dump_c_options(a) 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 // 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}"') verror('Unable to write response file to "${out_name_cmd_line}"')
} }
cmd := '"${r.full_cl_exe_path}" "@${out_name_cmd_line}"' cmd := '"${r.full_cl_exe_path}" "@${out_name_cmd_line}"'