diff --git a/base/c.jl b/base/c.jl index f91f9cffb3867..8f76d7dc5ddd8 100644 --- a/base/c.jl +++ b/base/c.jl @@ -414,6 +414,18 @@ function transcode(::Type{UInt8}, src::AbstractVector{UInt16}) return dst end +function unsafe_string(p::Ptr{T}, length::Integer) where {T<:Union{UInt16,UInt32,Cwchar_t}} + transcode(String, unsafe_wrap(Array, p, length; own=false)) +end +function unsafe_string(cw::Cwstring) + p = convert(Ptr{Cwchar_t}, cw) + n = 1 + while unsafe_load(p, n) != 0 + n += 1 + end + return unsafe_string(p, n - 1) +end + # deferring (or un-deferring) ctrl-c handler for external C code that # is not interrupt safe (see also issue #2622). The sigatomic_begin/end # functions should always be called in matched pairs, ideally via: diff --git a/test/ccall.jl b/test/ccall.jl index ea50cdea55d1a..ccb959aaad23d 100644 --- a/test/ccall.jl +++ b/test/ccall.jl @@ -1686,3 +1686,18 @@ end @ccall free(strp[]::Cstring)::Cvoid @test str == "hi+1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-1.1-2.2-3.3-4.4-5.5-6.6-7.7-8.8-9.9\n" end + +@testset "Cwstring" begin + n = 100 + buffer = Array{Cwchar_t}(undef, n) + if Sys.iswindows() + # sprintf throws an error on Windows, see https://github.com/JuliaLang/julia/pull/36040#issuecomment-634774055 + len = @ccall swprintf_s(buffer::Ptr{Cwchar_t}, n::Csize_t, "α+%ls=%hhd"::Cwstring; "β"::Cwstring, 0xf::UInt8)::Cint + else + len = @ccall swprintf(buffer::Ptr{Cwchar_t}, n::Csize_t, "α+%ls=%hhd"::Cwstring; "β"::Cwstring, 0xf::UInt8)::Cint + end + str = GC.@preserve buffer unsafe_string(pointer(buffer), len) + @test str == "α+β=15" + str = GC.@preserve buffer unsafe_string(Cwstring(pointer(buffer))) + @test str == "α+β=15" +end