Coverage Report

Created: 2026-10-15 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython3/Modules/_localemodule.c
Line
Count
Source
1
/***********************************************************
2
Copyright (C) 1997, 2002, 2003, 2007, 2008 Martin von Loewis
3
4
Permission to use, copy, modify, and distribute this software and its
5
documentation for any purpose and without fee is hereby granted,
6
provided that the above copyright notice appear in all copies.
7
8
This software comes with no warranty. Use at your own risk.
9
10
******************************************************************/
11
12
#include "Python.h"
13
#include "pycore_fileutils.h"     // _Py_GetLocaleconvNumeric()
14
#include "pycore_pymem.h"         // _PyMem_Strdup()
15
16
#include <locale.h>               // setlocale()
17
#include <string.h>               // strlen()
18
#ifdef HAVE_ERRNO_H
19
#  include <errno.h>              // errno
20
#endif
21
#ifdef HAVE_LANGINFO_H
22
#  include <langinfo.h>           // nl_langinfo()
23
#endif
24
#ifdef HAVE_LIBINTL_H
25
#  include <libintl.h>
26
#endif
27
#ifdef MS_WINDOWS
28
#  ifndef WIN32_LEAN_AND_MEAN
29
#    define WIN32_LEAN_AND_MEAN
30
#  endif
31
#  include <windows.h>
32
#endif
33
34
PyDoc_STRVAR(locale__doc__, "Support for POSIX locales.");
35
36
typedef struct _locale_state {
37
    PyObject *Error;
38
} _locale_state;
39
40
static inline _locale_state*
41
get_locale_state(PyObject *m)
42
305
{
43
305
    void *state = PyModule_GetState(m);
44
305
    assert(state != NULL);
45
305
    return (_locale_state *)state;
46
305
}
47
48
#include "clinic/_localemodule.c.h"
49
50
/*[clinic input]
51
module _locale
52
[clinic start generated code]*/
53
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ed98569b726feada]*/
54
55
/* support functions for formatting floating-point numbers */
56
57
/* the grouping is terminated by either 0 or CHAR_MAX */
58
static PyObject*
59
copy_grouping(const char* s)
60
0
{
61
0
    int i;
62
0
    PyObject *result, *val = NULL;
63
64
0
    if (s[0] == '\0') {
65
        /* empty string: no grouping at all */
66
0
        return PyList_New(0);
67
0
    }
68
69
0
    for (i = 0; s[i] != '\0' && s[i] != CHAR_MAX; i++)
70
0
        ; /* nothing */
71
72
0
    result = PyList_New(i+1);
73
0
    if (!result)
74
0
        return NULL;
75
76
0
    i = -1;
77
0
    do {
78
0
        i++;
79
0
        val = PyLong_FromLong(s[i]);
80
0
        if (val == NULL) {
81
0
            Py_DECREF(result);
82
0
            return NULL;
83
0
        }
84
0
        PyList_SET_ITEM(result, i, val);
85
0
    } while (s[i] != '\0' && s[i] != CHAR_MAX);
86
87
0
    return result;
88
0
}
89
90
#if defined(MS_WINDOWS)
91
92
// 16 is the number of elements in the szCodePage field
93
// of the __crt_locale_strings structure.
94
#define MAX_CP_LEN 15
95
96
static int
97
check_locale_name(const char *locale, const char *end)
98
{
99
    size_t len = end ? (size_t)(end - locale) : strlen(locale);
100
    const char *dot = memchr(locale, '.', len);
101
    if (dot && locale + len - dot - 1 > MAX_CP_LEN) {
102
        return -1;
103
    }
104
    return 0;
105
}
106
107
static int
108
check_locale_name_all(const char *locale)
109
{
110
    const char *start = locale;
111
    while (1) {
112
        const char *end = strchr(start, ';');
113
        if (check_locale_name(start, end) < 0) {
114
            return -1;
115
        }
116
        if (end == NULL) {
117
            break;
118
        }
119
        start = end + 1;
120
    }
121
    return 0;
122
}
123
#endif
124
125
/*[clinic input]
126
_locale.setlocale
127
128
    category: int
129
    locale: str(accept={str, NoneType}) = None
130
    /
131
132
Activates/queries locale processing.
133
[clinic start generated code]*/
134
135
static PyObject *
136
_locale_setlocale_impl(PyObject *module, int category, const char *locale)
137
/*[clinic end generated code: output=a0e777ae5d2ff117 input=b53449b63407179b]*/
138
0
{
139
0
    char *result;
140
0
    PyObject *result_object;
141
142
#if defined(MS_WINDOWS)
143
    if (category < LC_MIN || category > LC_MAX)
144
    {
145
        PyErr_SetString(get_locale_state(module)->Error,
146
                        "invalid locale category");
147
        return NULL;
148
    }
149
    if (locale) {
150
        if ((category == LC_ALL
151
             ? check_locale_name_all(locale)
152
             : check_locale_name(locale, NULL)) < 0)
153
        {
154
            /* Debug assertion failure on Windows.
155
             * _Py_BEGIN_SUPPRESS_IPH/_Py_END_SUPPRESS_IPH do not help. */
156
            PyErr_SetString(get_locale_state(module)->Error,
157
                "unsupported locale setting");
158
            return NULL;
159
        }
160
    }
161
#endif
162
163
0
    if (locale) {
164
        /* set locale */
165
0
        result = setlocale(category, locale);
166
0
        if (!result) {
167
            /* operation failed, no setting was changed */
168
0
            PyErr_SetString(get_locale_state(module)->Error,
169
0
                            "unsupported locale setting");
170
0
            return NULL;
171
0
        }
172
0
        result_object = PyUnicode_DecodeLocale(result, NULL);
173
0
        if (!result_object)
174
0
            return NULL;
175
0
    } else {
176
        /* get locale */
177
0
        result = setlocale(category, NULL);
178
0
        if (!result) {
179
0
            PyErr_SetString(get_locale_state(module)->Error,
180
0
                            "locale query failed");
181
0
            return NULL;
182
0
        }
183
0
        result_object = PyUnicode_DecodeLocale(result, NULL);
184
0
    }
185
0
    return result_object;
186
0
}
187
188
static int
189
locale_is_ascii(const char *str)
190
0
{
191
0
    return (strlen(str) == 1 && ((unsigned char)str[0]) <= 127);
192
0
}
193
194
static int
195
is_all_ascii(const char *str)
196
0
{
197
0
    for (; *str; str++) {
198
0
        if ((unsigned char)*str > 127) {
199
0
            return 0;
200
0
        }
201
0
    }
202
0
    return 1;
203
0
}
204
205
static int
206
locale_decode_monetary(PyObject *dict, struct lconv *lc)
207
0
{
208
0
#ifndef MS_WINDOWS
209
0
    int change_locale;
210
0
    change_locale = (!locale_is_ascii(lc->int_curr_symbol)
211
0
                     || !locale_is_ascii(lc->currency_symbol)
212
0
                     || !locale_is_ascii(lc->mon_decimal_point)
213
0
                     || !locale_is_ascii(lc->mon_thousands_sep));
214
215
    /* Keep a copy of the LC_CTYPE locale */
216
0
    char *oldloc = NULL, *loc = NULL;
217
0
    if (change_locale) {
218
0
        oldloc = setlocale(LC_CTYPE, NULL);
219
0
        if (!oldloc) {
220
0
            PyErr_SetString(PyExc_RuntimeWarning,
221
0
                            "failed to get LC_CTYPE locale");
222
0
            return -1;
223
0
        }
224
225
0
        oldloc = _PyMem_Strdup(oldloc);
226
0
        if (!oldloc) {
227
0
            PyErr_NoMemory();
228
0
            return -1;
229
0
        }
230
231
0
        loc = setlocale(LC_MONETARY, NULL);
232
0
        if (loc != NULL && strcmp(loc, oldloc) == 0) {
233
0
            loc = NULL;
234
0
        }
235
236
0
        if (loc != NULL) {
237
            /* Only set the locale temporarily the LC_CTYPE locale
238
               to the LC_MONETARY locale if the two locales are different and
239
               at least one string is non-ASCII. */
240
0
            setlocale(LC_CTYPE, loc);
241
0
        }
242
0
    }
243
244
0
#define GET_LOCALE_STRING(ATTR) PyUnicode_DecodeLocale(lc->ATTR, NULL)
245
#else  /* MS_WINDOWS */
246
/* Use _W_* fields of Windows struct lconv */
247
#define GET_LOCALE_STRING(ATTR) PyUnicode_FromWideChar(lc->_W_ ## ATTR, -1)
248
#endif /* MS_WINDOWS */
249
250
0
    int res = -1;
251
252
0
#define RESULT_STRING(ATTR) \
253
0
    do { \
254
0
        PyObject *obj; \
255
0
        obj = GET_LOCALE_STRING(ATTR); \
256
0
        if (obj == NULL) { \
257
0
            goto done; \
258
0
        } \
259
0
        if (PyDict_SetItemString(dict, Py_STRINGIFY(ATTR), obj) < 0) { \
260
0
            Py_DECREF(obj); \
261
0
            goto done; \
262
0
        } \
263
0
        Py_DECREF(obj); \
264
0
    } while (0)
265
266
0
    RESULT_STRING(int_curr_symbol);
267
0
    RESULT_STRING(currency_symbol);
268
0
    RESULT_STRING(mon_decimal_point);
269
0
    RESULT_STRING(mon_thousands_sep);
270
0
#undef RESULT_STRING
271
0
#undef GET_LOCALE_STRING
272
273
0
    res = 0;
274
275
0
done:
276
0
#ifndef MS_WINDOWS
277
0
    if (loc != NULL) {
278
0
        setlocale(LC_CTYPE, oldloc);
279
0
    }
280
0
    PyMem_Free(oldloc);
281
0
#endif
282
0
    return res;
283
0
}
284
285
/*[clinic input]
286
_locale.localeconv
287
288
Returns numeric and monetary locale-specific parameters.
289
[clinic start generated code]*/
290
291
static PyObject *
292
_locale_localeconv_impl(PyObject *module)
293
/*[clinic end generated code: output=43a54515e0a2aef5 input=f1132d15accf4444]*/
294
0
{
295
0
    PyObject* result;
296
0
    struct lconv *lc;
297
0
    PyObject *x;
298
299
0
    result = PyDict_New();
300
0
    if (!result) {
301
0
        return NULL;
302
0
    }
303
304
    /* if LC_NUMERIC is different in the C library, use saved value */
305
0
    lc = localeconv();
306
307
    /* hopefully, the localeconv result survives the C library calls
308
       involved herein */
309
310
0
#define RESULT(key, obj)\
311
0
    do { \
312
0
        if (obj == NULL) \
313
0
            goto failed; \
314
0
        if (PyDict_SetItemString(result, key, obj) < 0) { \
315
0
            Py_DECREF(obj); \
316
0
            goto failed; \
317
0
        } \
318
0
        Py_DECREF(obj); \
319
0
    } while (0)
320
321
#ifdef MS_WINDOWS
322
/* Use _W_* fields of Windows struct lconv */
323
#define GET_LOCALE_STRING(ATTR) PyUnicode_FromWideChar(lc->_W_ ## ATTR, -1)
324
#else
325
0
#define GET_LOCALE_STRING(ATTR) PyUnicode_DecodeLocale(lc->ATTR, NULL)
326
0
#endif
327
0
#define RESULT_STRING(s)\
328
0
    do { \
329
0
        x = GET_LOCALE_STRING(s); \
330
0
        RESULT(#s, x); \
331
0
    } while (0)
332
333
0
#define RESULT_INT(i)\
334
0
    do { \
335
0
        x = PyLong_FromLong(lc->i); \
336
0
        RESULT(#i, x); \
337
0
    } while (0)
338
339
    /* Monetary information: LC_MONETARY encoding */
340
0
    if (locale_decode_monetary(result, lc) < 0) {
341
0
        goto failed;
342
0
    }
343
0
    x = copy_grouping(lc->mon_grouping);
344
0
    RESULT("mon_grouping", x);
345
346
0
    RESULT_STRING(positive_sign);
347
0
    RESULT_STRING(negative_sign);
348
0
    RESULT_INT(int_frac_digits);
349
0
    RESULT_INT(frac_digits);
350
0
    RESULT_INT(p_cs_precedes);
351
0
    RESULT_INT(p_sep_by_space);
352
0
    RESULT_INT(n_cs_precedes);
353
0
    RESULT_INT(n_sep_by_space);
354
0
    RESULT_INT(p_sign_posn);
355
0
    RESULT_INT(n_sign_posn);
356
357
    /* Numeric information: LC_NUMERIC encoding */
358
0
    PyObject *decimal_point = NULL, *thousands_sep = NULL;
359
0
    if (_Py_GetLocaleconvNumeric(lc, &decimal_point, &thousands_sep) < 0) {
360
0
        Py_XDECREF(decimal_point);
361
0
        Py_XDECREF(thousands_sep);
362
0
        goto failed;
363
0
    }
364
365
0
    if (PyDict_SetItemString(result, "decimal_point", decimal_point) < 0) {
366
0
        Py_DECREF(decimal_point);
367
0
        Py_DECREF(thousands_sep);
368
0
        goto failed;
369
0
    }
370
0
    Py_DECREF(decimal_point);
371
372
0
    if (PyDict_SetItemString(result, "thousands_sep", thousands_sep) < 0) {
373
0
        Py_DECREF(thousands_sep);
374
0
        goto failed;
375
0
    }
376
0
    Py_DECREF(thousands_sep);
377
378
0
    x = copy_grouping(lc->grouping);
379
0
    RESULT("grouping", x);
380
381
0
    return result;
382
383
0
  failed:
384
0
    Py_DECREF(result);
385
0
    return NULL;
386
387
0
#undef RESULT
388
0
#undef RESULT_STRING
389
0
#undef RESULT_INT
390
0
#undef GET_LOCALE_STRING
391
0
}
392
393
#if defined(HAVE_WCSCOLL)
394
395
/*[clinic input]
396
_locale.strcoll
397
398
    os1: unicode
399
    os2: unicode
400
    /
401
402
Compares two strings according to the locale.
403
[clinic start generated code]*/
404
405
static PyObject *
406
_locale_strcoll_impl(PyObject *module, PyObject *os1, PyObject *os2)
407
/*[clinic end generated code: output=82ddc6d62c76d618 input=693cd02bcbf38dd8]*/
408
0
{
409
0
    PyObject *result = NULL;
410
0
    wchar_t *ws1 = NULL, *ws2 = NULL;
411
412
    /* Convert the unicode strings to wchar[]. */
413
0
    ws1 = PyUnicode_AsWideCharString(os1, NULL);
414
0
    if (ws1 == NULL)
415
0
        goto done;
416
0
    ws2 = PyUnicode_AsWideCharString(os2, NULL);
417
0
    if (ws2 == NULL)
418
0
        goto done;
419
    /* Collate the strings. */
420
0
    result = PyLong_FromLong(wcscoll(ws1, ws2));
421
0
  done:
422
    /* Deallocate everything. */
423
0
    if (ws1) PyMem_Free(ws1);
424
0
    if (ws2) PyMem_Free(ws2);
425
0
    return result;
426
0
}
427
#endif
428
429
#ifdef HAVE_WCSXFRM
430
431
/*[clinic input]
432
_locale.strxfrm
433
434
    string as str: unicode
435
    /
436
437
Return a string that can be used as a key for locale-aware comparisons.
438
[clinic start generated code]*/
439
440
static PyObject *
441
_locale_strxfrm_impl(PyObject *module, PyObject *str)
442
/*[clinic end generated code: output=3081866ebffc01af input=1378bbe6a88b4780]*/
443
0
{
444
0
    Py_ssize_t n1;
445
0
    wchar_t *s = NULL, *buf = NULL;
446
0
    wchar_t dummy[1];
447
0
    size_t n2;
448
0
    PyObject *result = NULL;
449
450
0
    s = PyUnicode_AsWideCharString(str, &n1);
451
0
    if (s == NULL)
452
0
        goto exit;
453
0
    if (wcslen(s) != (size_t)n1) {
454
0
        PyErr_SetString(PyExc_ValueError,
455
0
                        "embedded null character");
456
0
        goto exit;
457
0
    }
458
459
0
    errno = 0;
460
    /* Query the size with a real one-element buffer: DragonFly BSD's
461
       wcsxfrm() crashes when the destination is NULL or the size is 0. */
462
0
    n2 = wcsxfrm(dummy, s, 1);
463
0
    if (errno && errno != ERANGE) {
464
0
        PyErr_SetFromErrno(PyExc_OSError);
465
0
        goto exit;
466
0
    }
467
0
    buf = PyMem_New(wchar_t, n2+1);
468
0
    if (!buf) {
469
0
        PyErr_NoMemory();
470
0
        goto exit;
471
0
    }
472
473
0
    errno = 0;
474
0
    n2 = wcsxfrm(buf, s, n2+1);
475
0
    if (errno) {
476
0
        PyErr_SetFromErrno(PyExc_OSError);
477
0
        goto exit;
478
0
    }
479
    /* The result is just a sequence of integers, they are not necessary
480
       Unicode code points, so PyUnicode_FromWideChar() cannot be used
481
       here. For example, 0xD83D 0xDC0D should not be larger than 0xFF41.
482
     */
483
0
#if SIZEOF_WCHAR_T == 4
484
0
    {
485
        /* Some codes can exceed the range of Unicode code points
486
           (0 - 0x10FFFF), so they cannot be directly used in
487
           PyUnicode_FromKindAndData(). They should be first encoded in
488
           a way that preserves the lexicographical order.
489
490
           Codes in the range 0-0xFFFF represent themself.
491
           Codes larger than 0xFFFF are encoded as a pair:
492
           * 0x1xxxx -- the highest 16 bits
493
           * 0x0xxxx -- the lowest 16 bits
494
         */
495
0
        size_t n3 = 0;
496
0
        for (size_t i = 0; i < n2; i++) {
497
0
            if ((Py_UCS4)buf[i] > 0x10000u) {
498
0
                n3++;
499
0
            }
500
0
        }
501
0
        if (n3) {
502
0
            n3 += n2; // no integer overflow
503
0
            Py_UCS4 *buf2 = PyMem_New(Py_UCS4, n3);
504
0
            if (buf2 == NULL) {
505
0
                PyErr_NoMemory();
506
0
                goto exit;
507
0
            }
508
0
            size_t j = 0;
509
0
            for (size_t i = 0; i < n2; i++) {
510
0
                Py_UCS4 c = (Py_UCS4)buf[i];
511
0
                if (c > 0x10000u) {
512
0
                    buf2[j++] = (c >> 16) | 0x10000u;
513
0
                    buf2[j++] = c & 0xFFFFu;
514
0
                }
515
0
                else {
516
0
                    buf2[j++] = c;
517
0
                }
518
0
            }
519
0
            assert(j == n3);
520
0
            result = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buf2, n3);
521
0
            PyMem_Free(buf2);
522
0
            goto exit;
523
0
        }
524
0
    }
525
0
#endif
526
0
    result = PyUnicode_FromKindAndData(sizeof(wchar_t), buf, n2);
527
0
exit:
528
0
    PyMem_Free(buf);
529
0
    PyMem_Free(s);
530
0
    return result;
531
0
}
532
#endif
533
534
#if defined(MS_WINDOWS)
535
536
/*[clinic input]
537
_locale._getdefaultlocale
538
539
[clinic start generated code]*/
540
541
static PyObject *
542
_locale__getdefaultlocale_impl(PyObject *module)
543
/*[clinic end generated code: output=e6254088579534c2 input=003ea41acd17f7c7]*/
544
{
545
    char encoding[20];
546
    char locale[100];
547
548
    PyOS_snprintf(encoding, sizeof(encoding), "cp%u", GetACP());
549
550
    if (GetLocaleInfoA(LOCALE_USER_DEFAULT,
551
                      LOCALE_SISO639LANGNAME,
552
                      locale, sizeof(locale))) {
553
        Py_ssize_t i = strlen(locale);
554
        locale[i++] = '_';
555
        if (GetLocaleInfoA(LOCALE_USER_DEFAULT,
556
                          LOCALE_SISO3166CTRYNAME,
557
                          locale+i, (int)(sizeof(locale)-i)))
558
            return Py_BuildValue("ss", locale, encoding);
559
    }
560
561
    /* cannot determine the language code (very unlikely) */
562
    return Py_BuildValue("Os", Py_None, encoding);
563
}
564
#endif
565
566
#ifdef HAVE_LANGINFO_H
567
/* On glibc, LC_TIME text items also have a wide (_NL_W*) form, named
568
   _NL_W<narrow name>, that nl_langinfo() returns as wchar_t*.  LANGINFO_NW
569
   marks the items that have no wide counterpart. */
570
#ifdef __GLIBC__
571
#  define LANGINFO(X, Y) {#X, X, Y, _NL_W ## X}
572
#  define LANGINFO_NW(X, Y) {#X, X, Y, 0}
573
#else
574
#  define LANGINFO(X, Y) {#X, X, Y}
575
#  define LANGINFO_NW(X, Y) {#X, X, Y}
576
#endif
577
static struct langinfo_constant{
578
    const char *name;
579
    int value;
580
    int category;
581
#ifdef __GLIBC__
582
    nl_item wide;  /* wide _NL_W* counterpart, or 0 if none */
583
#endif
584
} langinfo_constants[] =
585
{
586
    /* These constants should exist on any langinfo implementation */
587
    LANGINFO(DAY_1, LC_TIME),
588
    LANGINFO(DAY_2, LC_TIME),
589
    LANGINFO(DAY_3, LC_TIME),
590
    LANGINFO(DAY_4, LC_TIME),
591
    LANGINFO(DAY_5, LC_TIME),
592
    LANGINFO(DAY_6, LC_TIME),
593
    LANGINFO(DAY_7, LC_TIME),
594
595
    LANGINFO(ABDAY_1, LC_TIME),
596
    LANGINFO(ABDAY_2, LC_TIME),
597
    LANGINFO(ABDAY_3, LC_TIME),
598
    LANGINFO(ABDAY_4, LC_TIME),
599
    LANGINFO(ABDAY_5, LC_TIME),
600
    LANGINFO(ABDAY_6, LC_TIME),
601
    LANGINFO(ABDAY_7, LC_TIME),
602
603
    LANGINFO(MON_1, LC_TIME),
604
    LANGINFO(MON_2, LC_TIME),
605
    LANGINFO(MON_3, LC_TIME),
606
    LANGINFO(MON_4, LC_TIME),
607
    LANGINFO(MON_5, LC_TIME),
608
    LANGINFO(MON_6, LC_TIME),
609
    LANGINFO(MON_7, LC_TIME),
610
    LANGINFO(MON_8, LC_TIME),
611
    LANGINFO(MON_9, LC_TIME),
612
    LANGINFO(MON_10, LC_TIME),
613
    LANGINFO(MON_11, LC_TIME),
614
    LANGINFO(MON_12, LC_TIME),
615
616
    LANGINFO(ABMON_1, LC_TIME),
617
    LANGINFO(ABMON_2, LC_TIME),
618
    LANGINFO(ABMON_3, LC_TIME),
619
    LANGINFO(ABMON_4, LC_TIME),
620
    LANGINFO(ABMON_5, LC_TIME),
621
    LANGINFO(ABMON_6, LC_TIME),
622
    LANGINFO(ABMON_7, LC_TIME),
623
    LANGINFO(ABMON_8, LC_TIME),
624
    LANGINFO(ABMON_9, LC_TIME),
625
    LANGINFO(ABMON_10, LC_TIME),
626
    LANGINFO(ABMON_11, LC_TIME),
627
    LANGINFO(ABMON_12, LC_TIME),
628
629
#ifdef RADIXCHAR
630
    /* The following are not available with glibc 2.0 */
631
    LANGINFO_NW(RADIXCHAR, LC_NUMERIC),
632
    LANGINFO_NW(THOUSEP, LC_NUMERIC),
633
    /* YESSTR and NOSTR are deprecated in glibc, since they are
634
       a special case of message translation, which should be rather
635
       done using gettext. So we don't expose it to Python in the
636
       first place.
637
    LANGINFO(YESSTR, LC_MESSAGES),
638
    LANGINFO(NOSTR, LC_MESSAGES),
639
    */
640
    LANGINFO_NW(CRNCYSTR, LC_MONETARY),
641
#endif
642
643
    LANGINFO(D_T_FMT, LC_TIME),
644
    LANGINFO(D_FMT, LC_TIME),
645
    LANGINFO(T_FMT, LC_TIME),
646
    LANGINFO(AM_STR, LC_TIME),
647
    LANGINFO(PM_STR, LC_TIME),
648
649
    /* The following constants are available only with XPG4, but...
650
       OpenBSD doesn't have CODESET but has T_FMT_AMPM, and doesn't have
651
       a few of the others.
652
       Solution: ifdef-test them all. */
653
#ifdef CODESET
654
    LANGINFO_NW(CODESET, LC_CTYPE),
655
#endif
656
#ifdef T_FMT_AMPM
657
    LANGINFO(T_FMT_AMPM, LC_TIME),
658
#endif
659
#ifdef ERA
660
    LANGINFO_NW(ERA, LC_TIME),
661
#endif
662
#ifdef ERA_D_FMT
663
    LANGINFO(ERA_D_FMT, LC_TIME),
664
#endif
665
#ifdef ERA_D_T_FMT
666
    LANGINFO(ERA_D_T_FMT, LC_TIME),
667
#endif
668
#ifdef ERA_T_FMT
669
    LANGINFO(ERA_T_FMT, LC_TIME),
670
#endif
671
#ifdef ALT_DIGITS
672
    LANGINFO(ALT_DIGITS, LC_TIME),
673
#endif
674
#ifdef YESEXPR
675
    LANGINFO_NW(YESEXPR, LC_MESSAGES),
676
#endif
677
#ifdef NOEXPR
678
    LANGINFO_NW(NOEXPR, LC_MESSAGES),
679
#endif
680
#ifdef _DATE_FMT
681
    /* This is not available in all glibc versions that have CODESET. */
682
    LANGINFO(_DATE_FMT, LC_TIME),
683
#endif
684
    {0, 0, 0}
685
};
686
687
/* Temporary make the LC_CTYPE locale to be the same as
688
 * the locale of the specified category. */
689
static int
690
change_locale(int category, char **oldloc)
691
0
{
692
    /* Keep a copy of the LC_CTYPE locale */
693
0
    *oldloc = setlocale(LC_CTYPE, NULL);
694
0
    if (!*oldloc) {
695
0
        PyErr_SetString(PyExc_RuntimeError, "failed to get LC_CTYPE locale");
696
0
        return -1;
697
0
    }
698
0
    *oldloc = _PyMem_Strdup(*oldloc);
699
0
    if (!*oldloc) {
700
0
        PyErr_NoMemory();
701
0
        return -1;
702
0
    }
703
704
    /* Set a new locale if it is different. */
705
0
    char *loc = setlocale(category, NULL);
706
0
    if (loc == NULL || strcmp(loc, *oldloc) == 0) {
707
0
        PyMem_Free(*oldloc);
708
0
        *oldloc = NULL;
709
0
        return 0;
710
0
    }
711
712
0
    setlocale(LC_CTYPE, loc);
713
0
    return 1;
714
0
}
715
716
/* Restore the old LC_CTYPE locale. */
717
static void
718
restore_locale(char *oldloc)
719
0
{
720
0
    if (oldloc != NULL) {
721
0
        setlocale(LC_CTYPE, oldloc);
722
0
        PyMem_Free(oldloc);
723
0
    }
724
0
}
725
726
#ifdef __GLIBC__
727
static PyObject *
728
decode_strings(const char *result)
729
0
{
730
    /* Convert a sequence of NUL-separated C strings to a Python string
731
     * containing semicolon separated items. */
732
0
    size_t i = 0;
733
0
    size_t count = 0;
734
0
    for (; result[i]; count++) {
735
0
        i += strlen(result + i) + 1;
736
0
    }
737
0
    char *buf = PyMem_Malloc(i);
738
0
    if (buf == NULL) {
739
0
        PyErr_NoMemory();
740
0
        return NULL;
741
0
    }
742
0
    memcpy(buf, result, i);
743
    /* Replace all NULs with semicolons. */
744
0
    i = 0;
745
0
    while (--count) {
746
0
        i += strlen(buf + i);
747
0
        buf[i++] = ';';
748
0
    }
749
0
    PyObject *pyresult = PyUnicode_DecodeLocale(buf, NULL);
750
0
    PyMem_Free(buf);
751
0
    return pyresult;
752
0
}
753
#endif
754
755
#ifdef __GLIBC__
756
static PyObject *
757
decode_wide_strings(const wchar_t *result, size_t max_count)
758
0
{
759
    /* Wide-character counterpart of decode_strings(): convert a sequence of
760
     * NUL-separated wchar_t strings to a str with semicolon-separated items. */
761
0
    size_t i = 0;
762
0
    size_t count = 0;
763
0
    for (; count < max_count && result[i]; count++) {
764
0
        i += wcslen(result + i) + 1;
765
0
    }
766
0
    wchar_t *buf = PyMem_New(wchar_t, i);
767
0
    if (buf == NULL) {
768
0
        PyErr_NoMemory();
769
0
        return NULL;
770
0
    }
771
0
    memcpy(buf, result, i * sizeof(wchar_t));
772
    /* Replace all NULs with semicolons. */
773
0
    i = 0;
774
0
    while (--count) {
775
0
        i += wcslen(buf + i);
776
0
        buf[i++] = L';';
777
0
    }
778
0
    PyObject *pyresult = PyUnicode_FromWideChar(buf, -1);
779
0
    PyMem_Free(buf);
780
0
    return pyresult;
781
0
}
782
#endif  /* __GLIBC__ */
783
784
/*[clinic input]
785
_locale.nl_langinfo
786
787
    key as item: int
788
    /
789
790
Return the value for the locale information associated with key.
791
[clinic start generated code]*/
792
793
static PyObject *
794
_locale_nl_langinfo_impl(PyObject *module, int item)
795
/*[clinic end generated code: output=6aea457b47e077a3 input=00798143eecfeddc]*/
796
0
{
797
0
    int i;
798
    /* Check whether this is a supported constant. GNU libc sometimes
799
       returns numeric values in the char* return value, which would
800
       crash PyUnicode_FromString.  */
801
0
    for (i = 0; langinfo_constants[i].name; i++) {
802
0
        if (langinfo_constants[i].value == item) {
803
0
#ifdef __GLIBC__
804
            /* Prefer the wide variant: it is decoded independently of the
805
               LC_CTYPE encoding. */
806
0
            nl_item wide = langinfo_constants[i].wide;
807
0
            if (wide) {
808
0
                const wchar_t *wresult = (const wchar_t *)nl_langinfo(wide);
809
0
                if (wresult == NULL) {
810
0
                    wresult = L"";
811
0
                }
812
                /* ALT_DIGITS is a sequence of NUL-separated strings. */
813
0
                if (item == ALT_DIGITS && *wresult) {
814
0
                    return decode_wide_strings(wresult, 100);
815
0
                }
816
0
                return PyUnicode_FromWideChar(wresult, -1);
817
0
            }
818
0
#endif
819
            /* Check NULL as a workaround for GNU libc's returning NULL
820
               instead of an empty string for nl_langinfo(ERA).  */
821
0
            const char *result = nl_langinfo(item);
822
0
            result = result != NULL ? result : "";
823
0
            char *oldloc = NULL;
824
0
            if (langinfo_constants[i].category != LC_CTYPE
825
0
                && *result && (
826
0
#ifdef __GLIBC__
827
                    // gh-133740: Always change the locale for ERA
828
0
                    item == ERA ||
829
0
#endif
830
0
                    !is_all_ascii(result))
831
0
                && change_locale(langinfo_constants[i].category, &oldloc) < 0)
832
0
            {
833
0
                return NULL;
834
0
            }
835
0
            PyObject *pyresult;
836
0
#ifdef __GLIBC__
837
            /* According to the POSIX specification the result must be
838
             * a sequence of semicolon-separated strings.
839
             * But in Glibc they are NUL-separated. */
840
0
            if (item == ERA && *result) {
841
0
                pyresult = decode_strings(result);
842
0
            }
843
0
            else
844
0
#endif
845
0
            {
846
0
                pyresult = PyUnicode_DecodeLocale(result, NULL);
847
0
            }
848
0
            restore_locale(oldloc);
849
0
            return pyresult;
850
0
        }
851
0
    }
852
0
    PyErr_SetString(PyExc_ValueError, "unsupported langinfo constant");
853
0
    return NULL;
854
0
}
855
#endif /* HAVE_LANGINFO_H */
856
857
#ifdef HAVE_LIBINTL_H
858
859
/*[clinic input]
860
_locale.gettext
861
862
    msg as in: str
863
    /
864
865
gettext(msg) -> string
866
867
Return translation of msg.
868
[clinic start generated code]*/
869
870
static PyObject *
871
_locale_gettext_impl(PyObject *module, const char *in)
872
/*[clinic end generated code: output=493bb4b38a4704fe input=949fc8efc2bb3bc3]*/
873
0
{
874
0
    return PyUnicode_DecodeLocale(gettext(in), NULL);
875
0
}
876
877
/*[clinic input]
878
_locale.dgettext
879
880
    domain: str(accept={str, NoneType})
881
    msg as in: str
882
    /
883
884
dgettext(domain, msg) -> string
885
886
Return translation of msg in domain.
887
[clinic start generated code]*/
888
889
static PyObject *
890
_locale_dgettext_impl(PyObject *module, const char *domain, const char *in)
891
/*[clinic end generated code: output=3c0cd5287b972c8f input=a277388a635109d8]*/
892
0
{
893
0
    return PyUnicode_DecodeLocale(dgettext(domain, in), NULL);
894
0
}
895
896
/*[clinic input]
897
_locale.dcgettext
898
899
    domain: str(accept={str, NoneType})
900
    msg as msgid: str
901
    category: int
902
    /
903
904
Return translation of msg in domain and category.
905
[clinic start generated code]*/
906
907
static PyObject *
908
_locale_dcgettext_impl(PyObject *module, const char *domain,
909
                       const char *msgid, int category)
910
/*[clinic end generated code: output=0f4cc4fce0aa283f input=ec5f8fed4336de67]*/
911
0
{
912
0
    return PyUnicode_DecodeLocale(dcgettext(domain,msgid,category), NULL);
913
0
}
914
915
/*[clinic input]
916
_locale.textdomain
917
918
    domain: str(accept={str, NoneType})
919
    /
920
921
Set the C library's textdmain to domain, returning the new domain.
922
[clinic start generated code]*/
923
924
static PyObject *
925
_locale_textdomain_impl(PyObject *module, const char *domain)
926
/*[clinic end generated code: output=7992df06aadec313 input=66359716f5eb1d38]*/
927
0
{
928
0
    domain = textdomain(domain);
929
0
    if (!domain) {
930
0
        PyErr_SetFromErrno(PyExc_OSError);
931
0
        return NULL;
932
0
    }
933
0
    return PyUnicode_DecodeLocale(domain, NULL);
934
0
}
935
936
/*[clinic input]
937
_locale.bindtextdomain
938
939
    domain: str
940
    dir as dirname_obj: object
941
    /
942
943
Bind the C library's domain to dir.
944
[clinic start generated code]*/
945
946
static PyObject *
947
_locale_bindtextdomain_impl(PyObject *module, const char *domain,
948
                            PyObject *dirname_obj)
949
/*[clinic end generated code: output=6d6f3c7b345d785c input=c0dff085acfe272b]*/
950
0
{
951
0
    const char *dirname, *current_dirname;
952
0
    PyObject *dirname_bytes = NULL, *result;
953
954
0
    if (!strlen(domain)) {
955
0
        PyErr_SetString(get_locale_state(module)->Error,
956
0
                        "domain must be a non-empty string");
957
0
        return 0;
958
0
    }
959
0
    if (dirname_obj != Py_None) {
960
0
        if (!PyUnicode_FSConverter(dirname_obj, &dirname_bytes))
961
0
            return NULL;
962
0
        dirname = PyBytes_AsString(dirname_bytes);
963
0
    } else {
964
0
        dirname_bytes = NULL;
965
0
        dirname = NULL;
966
0
    }
967
0
    current_dirname = bindtextdomain(domain, dirname);
968
0
    if (current_dirname == NULL) {
969
0
        PyErr_SetFromErrno(PyExc_OSError);
970
0
        Py_XDECREF(dirname_bytes);
971
0
        return NULL;
972
0
    }
973
0
    result = PyUnicode_DecodeLocale(current_dirname, NULL);
974
0
    Py_XDECREF(dirname_bytes);
975
0
    return result;
976
0
}
977
978
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
979
980
/*[clinic input]
981
_locale.bind_textdomain_codeset
982
983
    domain: str
984
    codeset: str(accept={str, NoneType})
985
    /
986
987
Bind the C library's domain to codeset.
988
[clinic start generated code]*/
989
990
static PyObject *
991
_locale_bind_textdomain_codeset_impl(PyObject *module, const char *domain,
992
                                     const char *codeset)
993
/*[clinic end generated code: output=fa452f9c8b1b9e89 input=23fbe3540400f259]*/
994
0
{
995
0
    codeset = bind_textdomain_codeset(domain, codeset);
996
0
    if (codeset) {
997
0
        return PyUnicode_DecodeLocale(codeset, NULL);
998
0
    }
999
0
    Py_RETURN_NONE;
1000
0
}
1001
#endif  // HAVE_BIND_TEXTDOMAIN_CODESET
1002
1003
#endif  // HAVE_LIBINTL_H
1004
1005
1006
/*[clinic input]
1007
_locale.getencoding
1008
1009
Get the current locale encoding.
1010
[clinic start generated code]*/
1011
1012
static PyObject *
1013
_locale_getencoding_impl(PyObject *module)
1014
/*[clinic end generated code: output=86b326b971872e46 input=6503d11e5958b360]*/
1015
0
{
1016
0
    return _Py_GetLocaleEncodingObject();
1017
0
}
1018
1019
1020
static struct PyMethodDef PyLocale_Methods[] = {
1021
    _LOCALE_SETLOCALE_METHODDEF
1022
    _LOCALE_LOCALECONV_METHODDEF
1023
#ifdef HAVE_WCSCOLL
1024
    _LOCALE_STRCOLL_METHODDEF
1025
#endif
1026
#ifdef HAVE_WCSXFRM
1027
    _LOCALE_STRXFRM_METHODDEF
1028
#endif
1029
#if defined(MS_WINDOWS)
1030
    _LOCALE__GETDEFAULTLOCALE_METHODDEF
1031
#endif
1032
#ifdef HAVE_LANGINFO_H
1033
    _LOCALE_NL_LANGINFO_METHODDEF
1034
#endif
1035
#ifdef HAVE_LIBINTL_H
1036
    _LOCALE_GETTEXT_METHODDEF
1037
    _LOCALE_DGETTEXT_METHODDEF
1038
    _LOCALE_DCGETTEXT_METHODDEF
1039
    _LOCALE_TEXTDOMAIN_METHODDEF
1040
    _LOCALE_BINDTEXTDOMAIN_METHODDEF
1041
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
1042
    _LOCALE_BIND_TEXTDOMAIN_CODESET_METHODDEF
1043
#endif
1044
#endif
1045
    _LOCALE_GETENCODING_METHODDEF
1046
  {NULL, NULL}
1047
};
1048
1049
static int
1050
_locale_exec(PyObject *module)
1051
5
{
1052
5
#ifdef HAVE_LANGINFO_H
1053
5
    int i;
1054
5
#endif
1055
5
#define ADD_INT(module, value)                                    \
1056
40
    do {                                                          \
1057
40
        if (PyModule_AddIntConstant(module, #value, value) < 0) { \
1058
0
            return -1;                                            \
1059
0
        }                                                         \
1060
40
    } while (0)
1061
1062
5
    ADD_INT(module, LC_CTYPE);
1063
5
    ADD_INT(module, LC_TIME);
1064
5
    ADD_INT(module, LC_COLLATE);
1065
5
    ADD_INT(module, LC_MONETARY);
1066
1067
5
#ifdef LC_MESSAGES
1068
5
    ADD_INT(module, LC_MESSAGES);
1069
5
#endif /* LC_MESSAGES */
1070
1071
5
    ADD_INT(module, LC_NUMERIC);
1072
5
    ADD_INT(module, LC_ALL);
1073
5
    ADD_INT(module, CHAR_MAX);
1074
1075
5
    _locale_state *state = get_locale_state(module);
1076
5
    state->Error = PyErr_NewException("locale.Error", NULL, NULL);
1077
5
    if (PyModule_AddObjectRef(module, "Error", state->Error) < 0) {
1078
0
        return -1;
1079
0
    }
1080
1081
5
#ifdef HAVE_LANGINFO_H
1082
285
    for (i = 0; langinfo_constants[i].name; i++) {
1083
280
        if (PyModule_AddIntConstant(module,
1084
280
                                    langinfo_constants[i].name,
1085
280
                                    langinfo_constants[i].value) < 0) {
1086
0
            return -1;
1087
0
        }
1088
280
    }
1089
5
#endif
1090
1091
5
    if (PyErr_Occurred()) {
1092
0
        return -1;
1093
0
    }
1094
5
    return 0;
1095
1096
5
#undef ADD_INT
1097
5
}
1098
1099
static struct PyModuleDef_Slot _locale_slots[] = {
1100
    _Py_ABI_SLOT,
1101
    {Py_mod_exec, _locale_exec},
1102
    {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
1103
    {Py_mod_gil, Py_MOD_GIL_NOT_USED},
1104
    {0, NULL}
1105
};
1106
1107
static int
1108
locale_traverse(PyObject *module, visitproc visit, void *arg)
1109
300
{
1110
300
    _locale_state *state = get_locale_state(module);
1111
300
    Py_VISIT(state->Error);
1112
300
    return 0;
1113
300
}
1114
1115
static int
1116
locale_clear(PyObject *module)
1117
0
{
1118
0
    _locale_state *state = get_locale_state(module);
1119
0
    Py_CLEAR(state->Error);
1120
0
    return 0;
1121
0
}
1122
1123
static void
1124
locale_free(void *module)
1125
0
{
1126
0
    locale_clear((PyObject*)module);
1127
0
}
1128
1129
static struct PyModuleDef _localemodule = {
1130
    PyModuleDef_HEAD_INIT,
1131
    "_locale",
1132
    locale__doc__,
1133
    sizeof(_locale_state),
1134
    PyLocale_Methods,
1135
    _locale_slots,
1136
    locale_traverse,
1137
    locale_clear,
1138
    locale_free,
1139
};
1140
1141
PyMODINIT_FUNC
1142
PyInit__locale(void)
1143
5
{
1144
5
    return PyModuleDef_Init(&_localemodule);
1145
5
}
1146
1147
/*
1148
Local variables:
1149
c-basic-offset: 4
1150
indent-tabs-mode: nil
1151
End:
1152
*/