From 71511d4ac8686c2220093cc01525311d9c88bc4e Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Sun, 21 Jan 2024 13:23:09 +0100 Subject: [PATCH] getlocalename_l: implement per SUS Base Specifications Issue 8 draft #include const char *getlocalename_l(int category, locale_t locobj); Most notably, we need a per-thread space to store the string returned if locobj is LC_GLOBAL_LOCALE. No errors are defined for getlocalename_l. So we can't use buffer allocation which might lead to an ENOMEM error. We have to use a "static" buffer in the per-thread state. Note that the feature test macro in locale.h is not quite correct. This needs to be fixed as soon as the Signed-off-by: Corinna Vinschen --- newlib/Makefile.in | 21 ++++++++ newlib/libc/include/locale.h | 5 ++ newlib/libc/include/sys/reent.h | 12 +++++ newlib/libc/locale/Makefile.inc | 1 + newlib/libc/locale/getlocalename_l.c | 77 ++++++++++++++++++++++++++++ 5 files changed, 116 insertions(+) create mode 100644 newlib/libc/locale/getlocalename_l.c diff --git a/newlib/Makefile.in b/newlib/Makefile.in index 9a32646ab..61a89ff65 100644 --- a/newlib/Makefile.in +++ b/newlib/Makefile.in @@ -353,6 +353,7 @@ check_PROGRAMS = @ELIX_LEVEL_1_FALSE@am__append_19 = \ @ELIX_LEVEL_1_FALSE@ libc/locale/duplocale.c \ @ELIX_LEVEL_1_FALSE@ libc/locale/freelocale.c \ +@ELIX_LEVEL_1_FALSE@ libc/locale/getlocalename_l.c \ @ELIX_LEVEL_1_FALSE@ libc/locale/lctype.c \ @ELIX_LEVEL_1_FALSE@ libc/locale/lmessages.c \ @ELIX_LEVEL_1_FALSE@ libc/locale/lnumeric.c \ @@ -1383,6 +1384,7 @@ am__objects_21 = $(am__objects_20) @ELIX_LEVEL_1_FALSE@am__objects_23 = \ @ELIX_LEVEL_1_FALSE@ libc/locale/libc_a-duplocale.$(OBJEXT) \ @ELIX_LEVEL_1_FALSE@ libc/locale/libc_a-freelocale.$(OBJEXT) \ +@ELIX_LEVEL_1_FALSE@ libc/locale/libc_a-getlocalename_l.$(OBJEXT) \ @ELIX_LEVEL_1_FALSE@ libc/locale/libc_a-lctype.$(OBJEXT) \ @ELIX_LEVEL_1_FALSE@ libc/locale/libc_a-lmessages.$(OBJEXT) \ @ELIX_LEVEL_1_FALSE@ libc/locale/libc_a-lnumeric.$(OBJEXT) \ @@ -3937,6 +3939,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ shared_machine_dir = @shared_machine_dir@ sharedstatedir = @sharedstatedir@ @@ -6602,6 +6605,9 @@ libc/locale/libc_a-duplocale.$(OBJEXT): libc/locale/$(am__dirstamp) \ libc/locale/$(DEPDIR)/$(am__dirstamp) libc/locale/libc_a-freelocale.$(OBJEXT): libc/locale/$(am__dirstamp) \ libc/locale/$(DEPDIR)/$(am__dirstamp) +libc/locale/libc_a-getlocalename_l.$(OBJEXT): \ + libc/locale/$(am__dirstamp) \ + libc/locale/$(DEPDIR)/$(am__dirstamp) libc/locale/libc_a-lctype.$(OBJEXT): libc/locale/$(am__dirstamp) \ libc/locale/$(DEPDIR)/$(am__dirstamp) libc/locale/libc_a-lmessages.$(OBJEXT): libc/locale/$(am__dirstamp) \ @@ -12774,6 +12780,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@libc/iconv/lib/$(DEPDIR)/libc_a-ucsconv.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@libc/locale/$(DEPDIR)/libc_a-duplocale.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@libc/locale/$(DEPDIR)/libc_a-freelocale.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@libc/locale/$(DEPDIR)/libc_a-getlocalename_l.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@libc/locale/$(DEPDIR)/libc_a-lctype.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@libc/locale/$(DEPDIR)/libc_a-lmessages.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@libc/locale/$(DEPDIR)/libc_a-lmonetary.Po@am__quote@ @@ -28041,6 +28048,20 @@ libc/locale/libc_a-freelocale.obj: libc/locale/freelocale.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libc_a_CPPFLAGS) $(CPPFLAGS) $(libc_a_CFLAGS) $(CFLAGS) -c -o libc/locale/libc_a-freelocale.obj `if test -f 'libc/locale/freelocale.c'; then $(CYGPATH_W) 'libc/locale/freelocale.c'; else $(CYGPATH_W) '$(srcdir)/libc/locale/freelocale.c'; fi` +libc/locale/libc_a-getlocalename_l.o: libc/locale/getlocalename_l.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libc_a_CPPFLAGS) $(CPPFLAGS) $(libc_a_CFLAGS) $(CFLAGS) -MT libc/locale/libc_a-getlocalename_l.o -MD -MP -MF libc/locale/$(DEPDIR)/libc_a-getlocalename_l.Tpo -c -o libc/locale/libc_a-getlocalename_l.o `test -f 'libc/locale/getlocalename_l.c' || echo '$(srcdir)/'`libc/locale/getlocalename_l.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libc/locale/$(DEPDIR)/libc_a-getlocalename_l.Tpo libc/locale/$(DEPDIR)/libc_a-getlocalename_l.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libc/locale/getlocalename_l.c' object='libc/locale/libc_a-getlocalename_l.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libc_a_CPPFLAGS) $(CPPFLAGS) $(libc_a_CFLAGS) $(CFLAGS) -c -o libc/locale/libc_a-getlocalename_l.o `test -f 'libc/locale/getlocalename_l.c' || echo '$(srcdir)/'`libc/locale/getlocalename_l.c + +libc/locale/libc_a-getlocalename_l.obj: libc/locale/getlocalename_l.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libc_a_CPPFLAGS) $(CPPFLAGS) $(libc_a_CFLAGS) $(CFLAGS) -MT libc/locale/libc_a-getlocalename_l.obj -MD -MP -MF libc/locale/$(DEPDIR)/libc_a-getlocalename_l.Tpo -c -o libc/locale/libc_a-getlocalename_l.obj `if test -f 'libc/locale/getlocalename_l.c'; then $(CYGPATH_W) 'libc/locale/getlocalename_l.c'; else $(CYGPATH_W) '$(srcdir)/libc/locale/getlocalename_l.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libc/locale/$(DEPDIR)/libc_a-getlocalename_l.Tpo libc/locale/$(DEPDIR)/libc_a-getlocalename_l.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libc/locale/getlocalename_l.c' object='libc/locale/libc_a-getlocalename_l.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libc_a_CPPFLAGS) $(CPPFLAGS) $(libc_a_CFLAGS) $(CFLAGS) -c -o libc/locale/libc_a-getlocalename_l.obj `if test -f 'libc/locale/getlocalename_l.c'; then $(CYGPATH_W) 'libc/locale/getlocalename_l.c'; else $(CYGPATH_W) '$(srcdir)/libc/locale/getlocalename_l.c'; fi` + libc/locale/libc_a-lctype.o: libc/locale/lctype.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libc_a_CPPFLAGS) $(CPPFLAGS) $(libc_a_CFLAGS) $(CFLAGS) -MT libc/locale/libc_a-lctype.o -MD -MP -MF libc/locale/$(DEPDIR)/libc_a-lctype.Tpo -c -o libc/locale/libc_a-lctype.o `test -f 'libc/locale/lctype.c' || echo '$(srcdir)/'`libc/locale/lctype.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libc/locale/$(DEPDIR)/libc_a-lctype.Tpo libc/locale/$(DEPDIR)/libc_a-lctype.Po diff --git a/newlib/libc/include/locale.h b/newlib/libc/include/locale.h index ec7f86119..e3a702a5e 100644 --- a/newlib/libc/include/locale.h +++ b/newlib/libc/include/locale.h @@ -76,6 +76,7 @@ struct __locale_t *_newlocale_r (struct _reent *, int, const char *, void _freelocale_r (struct _reent *, struct __locale_t *); struct __locale_t *_duplocale_r (struct _reent *, struct __locale_t *); struct __locale_t *_uselocale_r (struct _reent *, struct __locale_t *); +const char *_getlocalename_l_r (struct _reent *, int, struct __locale_t *); #ifndef _REENT_ONLY @@ -89,6 +90,10 @@ locale_t duplocale (locale_t); locale_t uselocale (locale_t); #endif /* __POSIX_VISIBLE >= 200809 */ +#if __POSIX_VISIBLE >= 200809 /* FIXME? Starting with issue 8 */ +const char *getlocalename_l (int, struct __locale_t *); +#endif + #endif /* _REENT_ONLY */ _END_STD_C diff --git a/newlib/libc/include/sys/reent.h b/newlib/libc/include/sys/reent.h index a02e7c2bd..4e60c3096 100644 --- a/newlib/libc/include/sys/reent.h +++ b/newlib/libc/include/sys/reent.h @@ -369,6 +369,9 @@ struct _misc_reent _mbstate_t _mbsrtowcs_state; _mbstate_t _wcrtomb_state; _mbstate_t _wcsrtombs_state; +#ifdef _MB_CAPABLE + char _getlocalename_l_buf[32 /*ENCODING + 1*/]; +#endif }; /* This version of _reent is laid out with "int"s in pairs, to help @@ -530,6 +533,7 @@ struct _reent _r->_misc->_wcrtomb_state.__value.__wch = 0; \ _r->_misc->_wcsrtombs_state.__count = 0; \ _r->_misc->_wcsrtombs_state.__value.__wch = 0; \ + _r->_misc->_getlocale_l_buf[0] = '\0'; \ _r->_misc->_l64a_buf[0] = '\0'; \ _r->_misc->_getdate_err = 0; \ } while (0) @@ -561,6 +565,7 @@ struct _reent #define _REENT_WCSRTOMBS_STATE(ptr) ((ptr)->_misc->_wcsrtombs_state) #define _REENT_L64A_BUF(ptr) ((ptr)->_misc->_l64a_buf) #define _REENT_GETDATE_ERR_P(ptr) (&((ptr)->_misc->_getdate_err)) +#define _REENT_GETLOCALENAME_L_BUF(ptr) ((ptr)->_misc->_getlocalename_l_buf) #define _REENT_SIGNAL_BUF(ptr) ((ptr)->_signal_buf) #else /* !_REENT_SMALL */ @@ -631,6 +636,10 @@ struct _reent _mbstate_t _mbrtoc16_state; _mbstate_t _mbrtoc32_state; #endif + /* No errors are defined for getlocalename_l. So we can't use + buffer allocation which might lead to an ENOMEM error. We + have to use a "static" buffer here instead. */ + char _getlocalename_l_buf[32 /* ENCODING_LEN + 1 */]; } _reent; #ifdef _REENT_BACKWARD_BINARY_COMPAT struct @@ -750,6 +759,7 @@ struct _reent #define _REENT_L64A_BUF(ptr) ((ptr)->_new._reent._l64a_buf) #define _REENT_SIGNAL_BUF(ptr) ((ptr)->_new._reent._signal_buf) #define _REENT_GETDATE_ERR_P(ptr) (&((ptr)->_new._reent._getdate_err)) +#define _REENT_GETLOCALENAME_L_BUF(ptr)((ptr)->_new._reent._getlocalename_l_buf) #endif /* !_REENT_SMALL */ @@ -842,6 +852,8 @@ extern _Thread_local char _tls_l64a_buf[8]; extern _Thread_local struct __locale_t *_tls_locale; #define _REENT_LOCALE(_ptr) (_tls_locale) extern _Thread_local _mbstate_t _tls_mblen_state; +#define _REENT_GETLOCALENAME_L_BUF(ptr) (_tls_getlocalename_l_buf) +extern _Thread_local char _tls_getlocalename_l_buf[32 /*ENCODING + 1*/]; #define _REENT_MBLEN_STATE(_ptr) (_tls_mblen_state) extern _Thread_local _mbstate_t _tls_mbrlen_state; #define _REENT_MBRLEN_STATE(_ptr) (_tls_mbrlen_state) diff --git a/newlib/libc/locale/Makefile.inc b/newlib/libc/locale/Makefile.inc index cef4131d0..0189643c2 100644 --- a/newlib/libc/locale/Makefile.inc +++ b/newlib/libc/locale/Makefile.inc @@ -8,6 +8,7 @@ if !ELIX_LEVEL_1 libc_a_SOURCES += \ %D%/duplocale.c \ %D%/freelocale.c \ + %D%/getlocalename_l.c \ %D%/lctype.c \ %D%/lmessages.c \ %D%/lnumeric.c \ diff --git a/newlib/libc/locale/getlocalename_l.c b/newlib/libc/locale/getlocalename_l.c new file mode 100644 index 000000000..7060c8df5 --- /dev/null +++ b/newlib/libc/locale/getlocalename_l.c @@ -0,0 +1,77 @@ +/* +FUNCTION + <>---create or modify a locale object + +INDEX + getlocalename_l + +INDEX + _getlocalename_l_r + +SYNOPSIS + #include + locale_t getlocalename_l(int <[category]>, locale_t <[locobj]>); + + locale_t _getlocalename_l_r(void *<[reent]>, int <[category]>, + locale_t <[locobj]>); + +DESCRIPTION +The <> function shall return the locale name for the +given locale category of the locale object locobj, or of the global +locale if locobj is the special locale object LC_GLOBAL_LOCALE. + +The category argument specifies the locale category to be queried. If +the value is LC_ALL or is not a supported locale category value (see +<>), <> shall fail. + +The behavior is undefined if the locobj argument is neither the special +locale object LC_GLOBAL_LOCALE nor a valid locale object handle. + +RETURNS +Upon successful completion, <> shall return a pointer +to a string containing the locale name; otherwise, a null pointer shall +be returned. + +If locobj is LC_GLOBAL_LOCALE, the returned string pointer might be +invalidated or the string content might be overwritten by a subsequent +call in the same thread to <> with LC_GLOBAL_LOCALE; +the returned string pointer might also be invalidated if the calling +thread is terminated. Otherwise, the returned string pointer and content +shall remain valid until the locale object locobj is used in a call to +<> or as the base argument in a successful call to +<>. + +No errors are defined. + +PORTABILITY +<> is POSIX-1.2008 since Base Specification Issue 8 +*/ + +#include +#include "setlocale.h" + +const char * +_getlocalename_l_r (struct _reent *ptr, int category, struct __locale_t *locobj) +{ + if (category <= LC_ALL || category > LC_MESSAGES) + return NULL; +#ifndef _MB_CAPABLE + return "C"; +#else + if (locobj == LC_GLOBAL_LOCALE) + { + /* getlocalename_l is supposed to return the value in a + thread-safe manner. This requires to copy over the + category string into thread-local storage. */ + strcpy (_REENT_GETLOCALENAME_L_BUF (ptr), + __get_global_locale ()->categories[category]); + } + return locobj->categories[category]; +#endif +} + +const char * +getlocalename_l (int category, struct __locale_t *locobj) +{ + return _getlocalename_l_r (_REENT, category, locobj); +}