#include <ctype.h>
#ifndef REGTEST
-
-#include <locale.h>
+#include <_PDCLIB_locale.h>
int isalnum( int c )
{
- return ( _PDCLIB_lconv.ctype[c].flags & ( _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_DIGIT ) );
+ return ( _PDCLIB_threadlocale()->_CType[c].flags & ( _PDCLIB_CTYPE_ALPHA | _PDCLIB_CTYPE_DIGIT ) );
}
#endif
#include <ctype.h>
#ifndef REGTEST
-
-#include <locale.h>
+#include <_PDCLIB_locale.h>
int isalpha( int c )
{
- return ( _PDCLIB_lconv.ctype[c].flags & _PDCLIB_CTYPE_ALPHA );
+ return ( _PDCLIB_threadlocale()->_CType[c].flags & _PDCLIB_CTYPE_ALPHA );
}
#endif
#include <ctype.h>
#ifndef REGTEST
-
-#include <locale.h>
+#include <_PDCLIB_locale.h>
int isblank( int c )
{
- return ( _PDCLIB_lconv.ctype[c].flags & _PDCLIB_CTYPE_BLANK );
+ return ( _PDCLIB_threadlocale()->_CType[c].flags & _PDCLIB_CTYPE_BLANK );
}
#endif
#include <ctype.h>
#ifndef REGTEST
-
-#include <locale.h>
+#include <_PDCLIB_locale.h>
int iscntrl( int c )
{
- return ( _PDCLIB_lconv.ctype[c].flags & _PDCLIB_CTYPE_CNTRL );
+ return ( _PDCLIB_threadlocale()->_CType[c].flags & _PDCLIB_CTYPE_CNTRL );
}
#endif
#include <ctype.h>
#ifndef REGTEST
-
-#include <locale.h>
+#include <_PDCLIB_locale.h>
int isdigit( int c )
{
- return ( _PDCLIB_lconv.ctype[c].flags & _PDCLIB_CTYPE_DIGIT );
+ return ( _PDCLIB_threadlocale()->_CType[c].flags & _PDCLIB_CTYPE_DIGIT );
}
#endif
#include <ctype.h>
#ifndef REGTEST
-
-#include <locale.h>
+#include <_PDCLIB_locale.h>
int isgraph( int c )
{
- return ( _PDCLIB_lconv.ctype[c].flags & _PDCLIB_CTYPE_GRAPH );
+ return ( _PDCLIB_threadlocale()->_CType[c].flags & _PDCLIB_CTYPE_GRAPH );
}
#endif
#include <ctype.h>
#ifndef REGTEST
-
-#include <locale.h>
+#include <_PDCLIB_locale.h>
int islower( int c )
{
- return ( _PDCLIB_lconv.ctype[c].flags & _PDCLIB_CTYPE_LOWER );
+ return ( _PDCLIB_threadlocale()->_CType[c].flags & _PDCLIB_CTYPE_LOWER );
}
#endif
#include <ctype.h>
#ifndef REGTEST
-
-#include <locale.h>
+#include <_PDCLIB_locale.h>
int isprint( int c )
{
- return ( _PDCLIB_lconv.ctype[c].flags & _PDCLIB_CTYPE_GRAPH ) || ( c == ' ' );
+ return ( _PDCLIB_threadlocale()->_CType[c].flags & _PDCLIB_CTYPE_GRAPH ) || ( c == ' ' );
}
#endif
#include <ctype.h>
#ifndef REGTEST
-
-#include <locale.h>
+#include <_PDCLIB_locale.h>
int ispunct( int c )
{
- return ( _PDCLIB_lconv.ctype[c].flags & _PDCLIB_CTYPE_PUNCT );
+ return ( _PDCLIB_threadlocale()->_CType[c].flags & _PDCLIB_CTYPE_PUNCT );
}
#endif
#include <ctype.h>
#ifndef REGTEST
-
-#include <locale.h>
+#include <_PDCLIB_locale.h>
int isspace( int c )
{
- return ( _PDCLIB_lconv.ctype[c].flags & _PDCLIB_CTYPE_SPACE );
+ return ( _PDCLIB_threadlocale()->_CType[c].flags & _PDCLIB_CTYPE_SPACE );
}
#endif
#include <ctype.h>
#ifndef REGTEST
-
-#include <locale.h>
+#include <_PDCLIB_locale.h>
int isupper( int c )
{
- return ( _PDCLIB_lconv.ctype[c].flags & _PDCLIB_CTYPE_UPPER );
+ return ( _PDCLIB_threadlocale()->_CType[c].flags & _PDCLIB_CTYPE_UPPER );
}
#endif
#include <ctype.h>
#ifndef REGTEST
-
-#include <locale.h>
+#include <_PDCLIB_locale.h>
int isxdigit( int c )
{
- return ( _PDCLIB_lconv.ctype[c].flags & _PDCLIB_CTYPE_XDIGT );
+ return ( _PDCLIB_threadlocale()->_CType[c].flags & _PDCLIB_CTYPE_XDIGT );
}
#endif
#include <ctype.h>
#ifndef REGTEST
-
-#include <locale.h>
+#include <_PDCLIB_locale.h>
int tolower( int c )
{
- return _PDCLIB_lconv.ctype[c].lower;
+ return _PDCLIB_threadlocale()->_CType[c].lower;
}
#endif
#include <ctype.h>
#ifndef REGTEST
-
-#include <locale.h>
+#include <_PDCLIB_locale.h>
int toupper( int c )
{
- return _PDCLIB_lconv.ctype[c].upper;
+ return _PDCLIB_threadlocale()->_CType[c].upper;
}
#endif
-/* $Id$ */
-
/* localeconv( void )
This file is part of the Public Domain C Library (PDCLib).
Permission is granted to use, modify, and / or redistribute at will.
*/
-#include <locale.h>
+#include <_PDCLIB_locale.h>
#ifndef REGTEST
struct lconv * localeconv( void )
{
- return &_PDCLIB_lconv;
+ return &_PDCLIB_threadlocale()->_Conv;
}
#endif
#ifndef REGTEST
#include <errno.h>
-#include <locale.h>
+#include <_PDCLIB_locale.h>
/* TODO: Doing this via a static array is not the way to do it. */
void perror( const char * s )
}
else
{
- fprintf( stderr, "%s\n", _PDCLIB_lconv._PDCLIB_errno_texts[errno] );
+ fprintf( stderr, "%s\n", _PDCLIB_threadlocale()->_ErrnoStr[errno] );
}
return;
}
#ifndef REGTEST
-#include <locale.h>
+#include <_PDCLIB_locale.h>
int strcoll( const char * s1, const char * s2 )
{
- while ( ( *s1 ) && ( _PDCLIB_lconv.ctype[(unsigned char)*s1].collation == _PDCLIB_lconv.ctype[(unsigned char)*s2].collation ) )
+ _PDCLIB_ctype_t * ctype = _PDCLIB_threadlocale()->_CType;
+
+ while ( ( *s1 ) && ( ctype[(unsigned char)*s1].collation == ctype[(unsigned char)*s2].collation ) )
{
++s1;
++s2;
}
- return ( _PDCLIB_lconv.ctype[(unsigned char)*s1].collation == _PDCLIB_lconv.ctype[(unsigned char)*s2].collation );
+ return ( ctype[(unsigned char)*s1].collation == ctype[(unsigned char)*s2].collation );
}
#endif
#ifndef REGTEST
-#include <locale.h>
+#include <_PDCLIB_locale.h>
/* TODO: Doing this via a static array is not the way to do it. */
char * strerror( int errnum )
}
else
{
- return _PDCLIB_lconv._PDCLIB_errno_texts[errnum];
+ return _PDCLIB_threadlocale()->_ErrnoStr[errnum];
}
}
#ifndef REGTEST
-#include <locale.h>
+#include <_PDCLIB_locale.h>
size_t strxfrm( char * _PDCLIB_restrict s1, const char * _PDCLIB_restrict s2, size_t n )
{
+ _PDCLIB_ctype_t *ctype = _PDCLIB_threadlocale()->_CType;
size_t len = strlen( s2 );
if ( len < n )
{
/* Cannot use strncpy() here as the filling of s1 with '\0' is not part
of the spec.
*/
- while ( n-- && ( *s1++ = _PDCLIB_lconv.ctype[(unsigned char)*s2++].collation ) );
+ while ( n-- && ( *s1++ = ctype[(unsigned char)*s2++].collation ) );
}
return len;
}
*/
struct lconv
{
- struct _PDCLIB_ctype_t * ctype; /* internal <ctype.h> information */
- char * _PDCLIB_errno_texts[_PDCLIB_ERRNO_MAX]; /* strerror() / perror() */
char * decimal_point; /* decimal point character */
char * thousands_sep; /* character for seperating groups of digits */
char * grouping; /* string indicating the size of digit groups */
char int_n_sign_posn; /* Same as above, for international format */
};
-/* This is strictly internal, and visible here for technical reasons only. */
-extern struct lconv _PDCLIB_lconv;
-
/* First arguments to setlocale().
TODO: Beware, values might change before v0.6 is released.
*/
struct lconv * localeconv( void ) _PDCLIB_nothrow;
#if _PDCLIB_POSIX_MIN(2008)
+
+/* POSIX locale type */
typedef _PDCLIB_locale_t locale_t;
+/* Global locale */
+extern struct _PDCLIB_locale _PDCLIB_global_locale;
+#define LC_GLOBAL_LOCALE (&_PDCLIB_global_locale)
+
/* Set the thread locale to newlocale
*
* If newlocale is (locale_t)0, then doesn't change the locale and just returns
*/
int * _PDCLIB_errno_func( void ) _PDCLIB_nothrow;
-/* -------------------------------------------------------------------------- */
-/* <ctype.h> lookup tables */
-/* -------------------------------------------------------------------------- */
-
-#define _PDCLIB_CTYPE_ALPHA 1
-#define _PDCLIB_CTYPE_BLANK 2
-#define _PDCLIB_CTYPE_CNTRL 4
-#define _PDCLIB_CTYPE_GRAPH 8
-#define _PDCLIB_CTYPE_PUNCT 16
-#define _PDCLIB_CTYPE_SPACE 32
-#define _PDCLIB_CTYPE_LOWER 64
-#define _PDCLIB_CTYPE_UPPER 128
-#define _PDCLIB_CTYPE_DIGIT 256
-#define _PDCLIB_CTYPE_XDIGT 512
-
-struct _PDCLIB_ctype_t
-{
- _PDCLIB_uint16_t flags;
- unsigned char upper;
- unsigned char lower;
- unsigned char collation;
-};
-
/* -------------------------------------------------------------------------- */
/* locale / wchar / uchar */
/* -------------------------------------------------------------------------- */
};
} _PDCLIB_mbstate_t;
-typedef struct _PDCLIB_charcodec _PDCLIB_charcodec_t;
+typedef struct _PDCLIB_charcodec *_PDCLIB_charcodec_t;
typedef struct _PDCLIB_locale *_PDCLIB_locale_t;
typedef struct lconv _PDCLIB_lconv_t;
#ifndef __PDCLIB_LOCALE_H
#define __PDCLIB_LOCALE_H __PDCLIB_LOCALE_H
+#include <_PDCLIB_int.h>
#include <locale.h>
+#include <threads.h>
+#include <stdlib.h>
-#define _PDCLIB_threadlocale() (uselocale(NULL))
+#define _PDCLIB_LOCALE_METHOD_TSS 't'
+#define _PDCLIB_LOCALE_METHOD_THREAD_LOCAL 'T'
+
+#if !defined(_PDCLIB_LOCALE_METHOD)
+ #error _PDCLIB_LOCALE_METHOD undefined: don't know where I'm storing the thread locale
+#elif _PDCLIB_LOCALE_METHOD == _PDCLIB_LOCALE_METHOD_TSS
+ extern tss_t _PDCLIB_locale_tss;
+ static inline locale_t _PDCLIB_threadlocale( void )
+ {
+ locale_t l = tss_get(_PDCLIB_locale_tss);
+ if(l == NULL)
+ l = &_PDCLIB_global_locale;
+ return l;
+ }
+
+ static inline void _PDCLIB_setthreadlocale( locale_t l )
+ {
+ if(tss_set(_PDCLIB_locale_tss, l) != thrd_success)
+ abort();
+ }
+#elif _PDCLIB_LOCALE_METHOD == _PDCLIB_LOCALE_METHOD_THREAD_LOCAL
+ extern thread_local locale_t _PDCLIB_locale_tls;
+ #define _PDCLIB_threadlocale() (_PDCLIB_locale_tls || &_PDCLIB_global_locale)
+ static inline locale_t _PDCLIB_threadlocale( void )
+ {
+ locale_t l = _PDCLIB_locale_tls;
+ if(l == NULL)
+ l = &_PDCLIB_global_locale;
+ return l;
+ }
+
+ static inline void _PDCLIB_setthreadlocale( locale_t l )
+ {
+ _PDCLIB_locale_tls = l;
+ }
+#else
+ #error Locale TSS method unspecified
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* <ctype.h> lookup tables */
+/* -------------------------------------------------------------------------- */
+
+#define _PDCLIB_CTYPE_ALPHA 1
+#define _PDCLIB_CTYPE_BLANK 2
+#define _PDCLIB_CTYPE_CNTRL 4
+#define _PDCLIB_CTYPE_GRAPH 8
+#define _PDCLIB_CTYPE_PUNCT 16
+#define _PDCLIB_CTYPE_SPACE 32
+#define _PDCLIB_CTYPE_LOWER 64
+#define _PDCLIB_CTYPE_UPPER 128
+#define _PDCLIB_CTYPE_DIGIT 256
+#define _PDCLIB_CTYPE_XDIGT 512
+
+typedef struct _PDCLIB_ctype
+{
+ _PDCLIB_uint16_t flags;
+ unsigned char upper;
+ unsigned char lower;
+ unsigned char collation;
+} _PDCLIB_ctype_t;
struct _PDCLIB_locale {
- struct _PDCLIB_charcodec *_Codec;
+ _PDCLIB_charcodec_t _Codec;
struct lconv _Conv;
+
+ /* ctype */
+ _PDCLIB_ctype_t *_CType;
+
+ /* perror/strerror */
+ char *_ErrnoStr[_PDCLIB_ERRNO_MAX];
};
#endif
return true;
}
-_PDCLIB_charcodec_t _PDCLIB_ascii_codec = {
+struct _PDCLIB_charcodec _PDCLIB_ascii_codec = {
.__mbstoc32s = asciitoc32,
.__c32stombs = c32toascii,
};
return true;
}
-_PDCLIB_charcodec_t _PDCLIB_latin1_codec = {
+struct _PDCLIB_charcodec _PDCLIB_latin1_codec = {
.__mbstoc32s = latin1toc32,
.__c32stombs = c32tolatin1,
};
END_CONVERSION;
}
-_PDCLIB_charcodec_t _PDCLIB_utf8_codec = {
+struct _PDCLIB_charcodec _PDCLIB_utf8_codec = {
.__mbstoc32s = utf8toc32,
.__c32stombs = c32toutf8,
};
#ifndef REGTEST
#include <_PDCLIB_io.h>
+#include <_PDCLIB_locale.h>
#include <threads.h>
/* In a POSIX system, stdin / stdout / stderr are equivalent to the (int) file
FILE * stdout = &_PDCLIB_sout;
FILE * stderr = &_PDCLIB_serr;
+tss_t _PDCLIB_locale_tss;
/* Todo: Better solution than this! */
__attribute__((constructor)) void init_stdio(void)
{
+ tss_create(&_PDCLIB_locale_tss, (tss_dtor_t) freelocale);
mtx_init(&stdin->lock, mtx_recursive);
mtx_init(&stdout->lock, mtx_recursive);
mtx_init(&stderr->lock, mtx_recursive);
1 kByte (+ 4 byte) of <ctype.h> data.
Each line: flags, lowercase, uppercase, collation.
*/
-static struct _PDCLIB_ctype_t _ctype[] = {
+static
+_PDCLIB_ctype_t global_ctype[] = {
{ /* EOF */ 0, 0, 0, 0 },
{ /* NUL */ _PDCLIB_CTYPE_CNTRL, 0x00, 0x00, 0x00 },
{ /* SOH */ _PDCLIB_CTYPE_CNTRL, 0x01, 0x01, 0x01 },
{ 0x00, 0xFF, 0xFF, 0xFF }
};
-struct lconv _PDCLIB_lconv = {
- /* _PDCLIB_ctype */ _ctype + 1,
- /* _PDCLIB_errno_texts */
- {
- /* no error */ (char *)"",
- /* ERANGE */ (char *)"ERANGE (Range error)",
- /* EDOM */ (char *)"EDOM (Domain error)",
- /* EILSEQ */ (char *)"EILSEQ (Illegal sequence)"
- },
+static struct lconv global_lconv = {
/* decimal_point */ (char *)".",
/* thousands_sep */ (char *)"",
/* grouping */ (char *)"",
/* int_n_sign_posn */ CHAR_MAX,
};
+extern struct _PDCLIB_charcodec _PDCLIB_ascii_codec;
+struct _PDCLIB_locale _PDCLIB_global_locale
+= {
+ ._Codec = &_PDCLIB_ascii_codec,
+ ._Conv = &global_lconv,
+ ._CType = &global_ctype[1],
+ ._ErrnoStr = {
+ /* no error */ (char *)"",
+ /* ERANGE */ (char *)"ERANGE (Range error)",
+ /* EDOM */ (char *)"EDOM (Domain error)",
+ /* EILSEQ */ (char *)"EILSEQ (Illegal sequence)"
+ },
+};
+
#endif
#ifdef TEST
/* TODO: Better document these */
+/* Locale --------------------------------------------------------------------*/
+
+/* Locale method. See _PDCLIB_locale.h */
+#define _PDCLIB_LOCALE_METHOD _PDCLIB_LOCALE_METHOD_TSS
+
/* I/O ---------------------------------------------------------------------- */
/* The default size for file buffers. Must be at least 256. */
/* TODO: Better document these */
+/* Locale --------------------------------------------------------------------*/
+
+/* Locale method. See _PDCLIB_locale.h */
+#define _PDCLIB_LOCALE_METHOD _PDCLIB_LOCALE_METHOD_TSS
+
/* I/O ---------------------------------------------------------------------- */
/* The default size for file buffers. Must be at least 256. */