getlocalename_l: implement per SUS Base Specifications Issue 8 draft

#include <locale.h>
  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 <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2024-01-21 13:23:09 +01:00
parent cb54031e01
commit 71511d4ac8
5 changed files with 116 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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 \

View File

@ -0,0 +1,77 @@
/*
FUNCTION
<<getlocalename_l>>---create or modify a locale object
INDEX
getlocalename_l
INDEX
_getlocalename_l_r
SYNOPSIS
#include <locale.h>
locale_t getlocalename_l(int <[category]>, locale_t <[locobj]>);
locale_t _getlocalename_l_r(void *<[reent]>, int <[category]>,
locale_t <[locobj]>);
DESCRIPTION
The <<getlocalename_l>> 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
<<setlocale>>), <<getlocalename_l>> 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, <<getlocalename_l>> 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 <<getlocalename_l>> 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
<<freelocale>> or as the base argument in a successful call to
<<newlocale>>.
No errors are defined.
PORTABILITY
<<getlocalename_l>> is POSIX-1.2008 since Base Specification Issue 8
*/
#include <newlib.h>
#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);
}