Skip to content

feat(libSceLibcInternal): implement num_put<wchar_t>::put and time_put<wchar_t>::put - #15745

Closed
B-Howell wants to merge 1 commit into
boykopovar:mainfrom
B-Howell:feat/r3-numput-wchar-put
Closed

B-Howell wants to merge 1 commit into
boykopovar:mainfrom
B-Howell:feat/r3-numput-wchar-put

Conversation

@B-Howell

@B-Howell B-Howell commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

What

Implements ten libSceLibcInternal exports that threw through NotImplemented_nid_no_patch on main: the public put members of std::num_put<wchar_t> and std::time_put<wchar_t> (the ostreambuf_iterator<wchar_t> instantiations), which std::wostream inserters for numbers and std::put_time on a wide stream reach through the stream's facets. It is the wchar_t counterpart of #15715 and is independent of it: no shared new file, no shared lines.

Export NID Stub on main Now
num_put<wchar_t>::put(..., bool) (...3putES3_RSt8ios_basewb) mY9FWooxqJY sceLibcInternalPending3_129 (Err.cpp) returns the facet's do_put(bool)
num_put<wchar_t>::put(..., long) (...basewl) USLhWp7sZoU sceLibcInternalPending3_132 returns do_put(long)
num_put<wchar_t>::put(..., unsigned long) (...basewm) qtpzdwMMCPc sceLibcInternalPending3_133 returns do_put(unsigned long)
num_put<wchar_t>::put(..., long long) (...basewx) ryykbHJ04Cw sceLibcInternalPending3_134 returns do_put(long long)
num_put<wchar_t>::put(..., unsigned long long) (...basewy) lmb3oBpMNPU sceLibcInternalPending3_135 returns do_put(unsigned long long)
num_put<wchar_t>::put(..., double) (...basewd) V7aIsVIsIIA sceLibcInternalPending3_130 returns do_put(double)
num_put<wchar_t>::put(..., long double) (...basewe) vCIFGeI6adI sceLibcInternalPending3_131 returns do_put(long double)
num_put<wchar_t>::put(..., const void*) (...basewPKv) xfOSCbCiY44 sceLibcInternalPending3_128 returns do_put(const void*)
time_put<wchar_t>::put(..., const tm*, char, char) (...basewPK2tmcc) Nt6eyVKm+Z4 sceLibcInternalPending4_072 (Export.cpp) returns the facet's do_put(spec, mod)
time_put<wchar_t>::put(..., const tm*, const wchar_t*, const wchar_t*) (...basewPK2tmPKwSB_) Sc0lXhQG5Ko sceLibcInternalPending4_071 walks the pattern, see below

Where the behaviour comes from:

  • The C++ standard ([facet.num.put.members]) defines each num_put::put as Returns: do_put(out, str, fill, val)., and [locale.time.put.members] the (spec, mod) overload as Returns: do_put(s, str, fill, t, format, modifier). The Dinkumware templates in the first microsoft/STL commit 219514876ea8, which serve char and wchar_t alike, write them the same way: return do_put(_Dest, _Iosbase, _Fill, _Val); (stl/inc/xlocnum L1189-L1227) and return do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier); (stl/inc/xloctime L680-L683). do_put is virtual, so each export calls the slot of the facet's own vtable. The wchar_t facets have the same slot order as the char ones already static_asserted on main (NumPutVtable 0x20 to 0x58, TimePutVtable::put 0x20); only the fill differs, a 16-bit wchar_t (GuestLocale::WideNumpunctFacet on main already uses std::uint16_t for it). GuestLocale::WideNumPutVtable and GuestLocale::WideTimePutVtable give those slots that fill type, with static_asserts.
  • The pattern overload follows the same commit's loop (stl/inc/xloctime L646-L678): use_facet<ctype<wchar_t>>(_Iosbase.getloc()), then for each character if (_Ctype_fac.narrow(*_Fmtfirst) != '%') copies it; a trailing % is copied; E, O, Q and # after % are modifiers, and a modifier at the end is copied as the original percent followed by the narrowed modifier (*_Dest++ = _Percent; *_Dest++ = _Specifier;); every other specifier goes to do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier), whose returned iterator is used for the rest of the pattern. It is LibcWideTimePutPattern_nid_no_patch in libc's LocaleSupport.cpp, declared in GuestLocale.hpp (the feat(libSceLibcInternal): implement the numpunct<char> members #14373 pattern; no new libc export), because it uses libc's existing FindFacet lookup by _ZNSt5ctypeIwE2idE. The export in libSceLibcInternal calls it.
  • Narrowing calls do_narrow(c, '\0'), the eleventh ctype<wchar_t> virtual in the same commit's declaration order (do_is x2, do_scan_is, do_scan_not, do_tolower x2, do_toupper x2, do_widen x2, do_narrow x2, stl/inc/xlocale L2940-L3036), with narrow(_Elem _Ch, char _Dflt = '\0'). After the four facet slots that is vtable offset 0x70, which matches the 18 slots of _ZTVSt5ctypeIwE on main (2 header + 4 facet + 12). GuestLocale::WideCtypeVtable records it with static_asserts (widen 0x60, narrow 0x70, narrowRange 0x78).
  • When the stream's locale has no ctype<wchar_t> facet (the classic locale has none in libc and there is no ctype<wchar_t>::_Getcat), the pattern is narrowed as libc's existing wctob does (unit < 0x80 ? unit : -1), a non-narrowable character giving the '\0' default. Dinkumware's classic ctype<wchar_t>::_Donarrow likewise converts through the C locale and returns the default when the character has no single-byte form.
  • Literal characters are written through the stream buffer as ostreambuf_iterator<wchar_t>::operator= does (if (!_Strbuf || traits_type::eq_int_type(_Traits::eof(), _Strbuf->sputc(_Right))) { _Failed = true; }, stl/inc/streambuf L555-L561): into the 16-bit put area while it has room, otherwise through overflow, whose -1 is the WEOF that libc's wide functions already use (GuestRune::Weof = 0xffffffff, fputwc returning -1). A null or failing buffer sets failed and later characters are still offered. This is the same shape as libc's existing PutCharacter for char.
  • Later microsoft/STL commits added _Is_valid_strftime_specifier checks that write ?; that is a later MSVC change, not Dinkumware's, so every specifier goes to do_put, as in 219514876ea8 and the standard.

The ten stubs are removed from Err.cpp and Export.cpp; the new exports are in core/libs/prx/libSceLibcInternal/FacetPutWide.cpp. The debt file drops their ten "prototype and behavior are unverified" lines and gets one entry for what stays unverified: the console's libSceLibcInternal.sprx was not read and no title was seen calling them.

tools/progress.py collect_libraries() on origin/main b11c7bf84f and on this branch: libSceLibcInternal done 92 -> 102 (+10), todo 1045 -> 1035 (-10), no new todo name; every other library unchanged. The repository total goes from 9921 to 9931 done of 37146, so +10 done and no new todo.

Tested

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

🤖 Generated with Claude Code

…t<wchar_t>::put

Each num_put<wchar_t>::put overload and time_put<wchar_t>::put(spec, mod)
returns do_put through the facet's own vtable with the 16-bit fill. The
pattern overload narrows through the stream's ctype<wchar_t>, copies
ordinary characters to the wide stream buffer and calls do_put for each
conversion, as the Dinkumware code in the first microsoft/STL commit does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the open PR limit Closed over the open PR limit: 1 without merged PRs, 20 with at least 1, none from 20 label Nov 4, 2026
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

Thank you for your contribution! Authors with no pull requests merged into main can have 1 open pull request at a time, authors with at least 1 merged can have 20, and from 20 merged there is no limit. This PR has been automatically closed and labeled "open PR limit" because that limit was reached. This is not a judgment of the quality of your changes: reopen it once one of your open pull requests is merged or closed.

@JJenkx

JJenkx commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Windows check of head 9f56f59a62, which already contains main b11c7bf84f.

Setup: Windows 11 Enterprise 22621, WinLibs GCC 15.2 UCRT, Release. The hosted Windows check does not run this test on pull requests.

  • guest_libc_internal_facet_put_wide passes in 3 of 3 runs. The host wchar_t is 16-bit on Windows, against the guest's 32-bit one.

AI-assisted: yes.

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

open PR limit Closed over the open PR limit: 1 without merged PRs, 20 with at least 1, none from 20

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants