[libc-commits] [libc] [libc] Add `ctype.h` locale variants (PR #102711)
Joseph Huber via libc-commits
libc-commits at lists.llvm.org
Tue Aug 13 12:32:43 PDT 2024
https://github.com/jhuber6 updated https://github.com/llvm/llvm-project/pull/102711
>From ae64d6a8be81aefb84837eff9ea0e51cfabc18c9 Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Fri, 9 Aug 2024 11:00:00 -0500
Subject: [PATCH 1/2] [libc] Initial support for 'locale.h' in the LLVM libc
Summary:
This patch adds the macros and entrypoints associated with the
`locale.h` entrypoints. These are mostly stubs, as we (for now and the
forseeable future) only expect to support the C and maybe C.UTF-8
locales in the LLVM libc.
---
libc/config/gpu/entrypoints.txt | 9 +++
libc/config/gpu/headers.txt | 1 +
libc/config/linux/x86_64/entrypoints.txt | 9 +++
libc/config/linux/x86_64/headers.txt | 1 +
libc/hdr/types/CMakeLists.txt | 9 +++
libc/hdr/types/locale_t.h | 22 ++++++
libc/include/CMakeLists.txt | 12 +++
libc/include/llvm-libc-macros/CMakeLists.txt | 6 ++
libc/include/llvm-libc-macros/locale-macros.h | 32 ++++++++
libc/include/llvm-libc-types/CMakeLists.txt | 2 +
libc/include/llvm-libc-types/locale_t.h | 22 ++++++
libc/include/llvm-libc-types/struct_lconv.h | 39 ++++++++++
libc/include/locale.h.def | 20 +++++
libc/newhdrgen/yaml/locale.yaml | 41 ++++++++++
libc/spec/stdc.td | 57 ++++++++++++++
libc/src/CMakeLists.txt | 1 +
libc/src/locale/CMakeLists.txt | 76 +++++++++++++++++++
libc/src/locale/duplocale.cpp | 21 +++++
libc/src/locale/duplocale.h | 22 ++++++
libc/src/locale/freelocale.cpp | 21 +++++
libc/src/locale/freelocale.h | 22 ++++++
libc/src/locale/locale.cpp | 21 +++++
libc/src/locale/locale.h | 36 +++++++++
libc/src/locale/localeconv.cpp | 49 ++++++++++++
libc/src/locale/localeconv.h | 22 ++++++
libc/src/locale/newlocale.cpp | 28 +++++++
libc/src/locale/newlocale.h | 22 ++++++
libc/src/locale/setlocale.cpp | 28 +++++++
libc/src/locale/setlocale.h | 22 ++++++
libc/src/locale/uselocale.cpp | 23 ++++++
libc/src/locale/uselocale.h | 22 ++++++
libc/test/src/CMakeLists.txt | 1 +
libc/test/src/locale/CMakeLists.txt | 25 ++++++
libc/test/src/locale/locale_test.cpp | 27 +++++++
libc/test/src/locale/localeconv_test.cpp | 17 +++++
35 files changed, 788 insertions(+)
create mode 100644 libc/hdr/types/locale_t.h
create mode 100644 libc/include/llvm-libc-macros/locale-macros.h
create mode 100644 libc/include/llvm-libc-types/locale_t.h
create mode 100644 libc/include/llvm-libc-types/struct_lconv.h
create mode 100644 libc/include/locale.h.def
create mode 100644 libc/newhdrgen/yaml/locale.yaml
create mode 100644 libc/src/locale/CMakeLists.txt
create mode 100644 libc/src/locale/duplocale.cpp
create mode 100644 libc/src/locale/duplocale.h
create mode 100644 libc/src/locale/freelocale.cpp
create mode 100644 libc/src/locale/freelocale.h
create mode 100644 libc/src/locale/locale.cpp
create mode 100644 libc/src/locale/locale.h
create mode 100644 libc/src/locale/localeconv.cpp
create mode 100644 libc/src/locale/localeconv.h
create mode 100644 libc/src/locale/newlocale.cpp
create mode 100644 libc/src/locale/newlocale.h
create mode 100644 libc/src/locale/setlocale.cpp
create mode 100644 libc/src/locale/setlocale.h
create mode 100644 libc/src/locale/uselocale.cpp
create mode 100644 libc/src/locale/uselocale.h
create mode 100644 libc/test/src/locale/CMakeLists.txt
create mode 100644 libc/test/src/locale/locale_test.cpp
create mode 100644 libc/test/src/locale/localeconv_test.cpp
diff --git a/libc/config/gpu/entrypoints.txt b/libc/config/gpu/entrypoints.txt
index b2644d2ebf386c..592c8cdb7ae778 100644
--- a/libc/config/gpu/entrypoints.txt
+++ b/libc/config/gpu/entrypoints.txt
@@ -231,6 +231,15 @@ set(TARGET_LIBC_ENTRYPOINTS
# wchar.h entrypoints
libc.src.wchar.wctob
+ # locale.h entrypoints
+ libc.src.locale.localeconv
+ libc.src.locale.duplocale
+ libc.src.locale.freelocale
+ libc.src.locale.localeconv
+ libc.src.locale.newlocale
+ libc.src.locale.setlocale
+ libc.src.locale.uselocale
+
# gpu/rpc.h entrypoints
libc.src.gpu.rpc_host_call
)
diff --git a/libc/config/gpu/headers.txt b/libc/config/gpu/headers.txt
index 99280b7563a80f..fc952c40f4daa2 100644
--- a/libc/config/gpu/headers.txt
+++ b/libc/config/gpu/headers.txt
@@ -16,6 +16,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.wchar
libc.include.uchar
libc.include.features
+ libc.include.locale
# Header for RPC extensions
libc.include.gpu_rpc
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 65c5757efe6274..e7c3c7db64abe5 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -982,6 +982,15 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.nanosleep
libc.src.time.time
+ # locale.h entrypoints
+ libc.src.locale.localeconv
+ libc.src.locale.duplocale
+ libc.src.locale.freelocale
+ libc.src.locale.localeconv
+ libc.src.locale.newlocale
+ libc.src.locale.setlocale
+ libc.src.locale.uselocale
+
# unistd.h entrypoints
libc.src.unistd.__llvm_libc_syscall
libc.src.unistd._exit
diff --git a/libc/config/linux/x86_64/headers.txt b/libc/config/linux/x86_64/headers.txt
index 77e454e64395df..881e149d9c40d3 100644
--- a/libc/config/linux/x86_64/headers.txt
+++ b/libc/config/linux/x86_64/headers.txt
@@ -33,6 +33,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.unistd
libc.include.wchar
libc.include.uchar
+ libc.include.locale
libc.include.arpa_inet
diff --git a/libc/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt
index 4fc28fd82e68db..f41576c07d99be 100644
--- a/libc/hdr/types/CMakeLists.txt
+++ b/libc/hdr/types/CMakeLists.txt
@@ -162,3 +162,12 @@ add_proxy_header_library(
libc.include.llvm-libc-types.cookie_io_functions_t
libc.include.stdio
)
+
+add_proxy_header_library(
+ locale_t
+ HDRS
+ locale_t.h
+ FULL_BUILD_DEPENDS
+ libc.include.llvm-libc-types.locale_t
+ libc.include.locale
+)
diff --git a/libc/hdr/types/locale_t.h b/libc/hdr/types/locale_t.h
new file mode 100644
index 00000000000000..485258b4616962
--- /dev/null
+++ b/libc/hdr/types/locale_t.h
@@ -0,0 +1,22 @@
+//===-- Definition of macros from locale_t.h ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_HDR_LOCALE_T_H
+#define LLVM_LIBC_HDR_LOCALE_T_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-types/locale_t.h"
+
+#else // overlay mode
+
+#error "type not available in overlay mode"
+
+#endif // LLVM_LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_LOCALE_T_H
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 2b6eb61782a632..733582c182735e 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -717,6 +717,18 @@ add_header_macro(
.llvm-libc-types.wchar_t
)
+add_header_macro(
+ locale
+ ../libc/newhdrgen/yaml/locale.yaml
+ locale.h.def
+ locale.h
+ DEPENDS
+ .llvm_libc_common_h
+ .llvm-libc-macros.locale_macros
+ .llvm-libc-types.locale_t
+ .llvm-libc-types.struct_lconv
+)
+
if(LIBC_TARGET_OS_IS_GPU)
file(MAKE_DIRECTORY ${LIBC_INCLUDE_DIR}/gpu)
diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt
index 60a8725f9ef63f..7b980232ba0429 100644
--- a/libc/include/llvm-libc-macros/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/CMakeLists.txt
@@ -295,3 +295,9 @@ add_macro_header(
HDR
elf-macros.h
)
+
+add_macro_header(
+ locale_macros
+ HDR
+ locale-macros.h
+)
diff --git a/libc/include/llvm-libc-macros/locale-macros.h b/libc/include/llvm-libc-macros/locale-macros.h
new file mode 100644
index 00000000000000..892f8b69f3a777
--- /dev/null
+++ b/libc/include/llvm-libc-macros/locale-macros.h
@@ -0,0 +1,32 @@
+//===-- Definition of macros from locale.h --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_MACROS_LOCALE_MACROS_H
+#define LLVM_LIBC_MACROS_LOCALE_MACROS_H
+
+#include "../llvm-libc-types/locale_t.h"
+
+#define LC_CTYPE 0
+#define LC_NUMERIC 1
+#define LC_TIME 2
+#define LC_COLLATE 3
+#define LC_MONETARY 4
+#define LC_MESSAGES 5
+#define LC_ALL 6
+
+#define LC_GLOBAL_LOCALE ((locale_t)(-1))
+
+#define LC_CTYPE_MASK (1 << LC_CTYPE)
+#define LC_NUMERIC_MASK (1 << LC_NUMERIC)
+#define LC_TIME_MASK (1 << LC_TIME)
+#define LC_COLLATE_MASK (1 << LC_COLLATE)
+#define LC_MONETARY_MASK (1 << LC_MONETARY)
+#define LC_MESSAGES_MASK (1 << LC_MESSAGES)
+#define LC_ALL_MASK 0x7fffffff
+
+#endif // LLVM_LIBC_MACROS_LOCALE_MACROS_H
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 0fa86e0152f9ba..583b84ccaae67c 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -142,3 +142,5 @@ DEPENDS
.fsblkcnt_t
.fsfilcnt_t
)
+add_header(locale_t HDR locale_t.h)
+add_header(struct_lconv HDR struct_lconv.h)
diff --git a/libc/include/llvm-libc-types/locale_t.h b/libc/include/llvm-libc-types/locale_t.h
new file mode 100644
index 00000000000000..6d783001acf9f2
--- /dev/null
+++ b/libc/include/llvm-libc-types/locale_t.h
@@ -0,0 +1,22 @@
+//===-- Definition of type locale_t ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TYPES_LOCALE_T_H
+#define LLVM_LIBC_TYPES_LOCALE_T_H
+
+#define NUM_LOCALE_CATEGORIES 6
+
+struct __locale_data;
+
+struct __locale_t {
+ struct __locale_data *data[NUM_LOCALE_CATEGORIES];
+};
+
+typedef struct __locale_t *locale_t;
+
+#endif // LLVM_LIBC_TYPES_LOCALE_T_H
diff --git a/libc/include/llvm-libc-types/struct_lconv.h b/libc/include/llvm-libc-types/struct_lconv.h
new file mode 100644
index 00000000000000..9d69f055484dad
--- /dev/null
+++ b/libc/include/llvm-libc-types/struct_lconv.h
@@ -0,0 +1,39 @@
+//===-- Definition of type lconv ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TYPES_LCONV_H
+#define LLVM_LIBC_TYPES_LCONV_H
+
+struct lconv {
+ char *decimal_point;
+ char *thousands_sep;
+ char *grouping;
+ char *mon_decimal_point;
+ char *mon_thousands_sep;
+ char *mon_grouping;
+ char *positive_sign;
+ char *negative_sign;
+ char *currency_symbol;
+ char frac_digits;
+ char p_cs_precedes;
+ char n_cs_precedes;
+ char p_sep_by_space;
+ char n_sep_by_space;
+ char p_sign_posn;
+ char n_sign_posn;
+ char *int_curr_symbol;
+ char int_frac_digits;
+ char int_p_cs_precedes;
+ char int_n_cs_precedes;
+ char int_p_sep_by_space;
+ char int_n_sep_by_space;
+ char int_p_sign_posn;
+ char int_n_sign_posn;
+};
+
+#endif // LLVM_LIBC_TYPES_LCONV_H
diff --git a/libc/include/locale.h.def b/libc/include/locale.h.def
new file mode 100644
index 00000000000000..516c6e6275e681
--- /dev/null
+++ b/libc/include/locale.h.def
@@ -0,0 +1,20 @@
+//===-- C standard library header locale.h --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_LOCALE_H
+#define LLVM_LIBC_LOCALE_H
+
+#include "__llvm-libc-common.h"
+
+#include "llvm-libc-macros/locale-macros.h"
+#include "llvm-libc-types/locale_t.h"
+#include "llvm-libc-types/struct_lconv.h"
+
+%%public_api()
+
+#endif // LLVM_LIBC_LOCALE_H
diff --git a/libc/newhdrgen/yaml/locale.yaml b/libc/newhdrgen/yaml/locale.yaml
new file mode 100644
index 00000000000000..7da7966ea730f6
--- /dev/null
+++ b/libc/newhdrgen/yaml/locale.yaml
@@ -0,0 +1,41 @@
+header: locale.h
+functions:
+ - name: localeconv
+ standards:
+ - stdc
+ return_type: struct lconv *
+ arguments:
+ - type: void
+ - name: duplocale
+ standards:
+ - stdc
+ return_type: locale_t
+ arguments:
+ - type: locale_t
+ - name: freelocale
+ standards:
+ - stdc
+ return_type: void
+ arguments:
+ - type: locale_t
+ - name: newlocale
+ standards:
+ - stdc
+ return_type: locale_t
+ arguments:
+ - type: int
+ - type: const char *
+ - type: locale_t
+ - name: setlocale
+ standards:
+ - stdc
+ return_type: char *
+ arguments:
+ - type: int
+ - type: const char *
+ - name: uselocale
+ standards:
+ - stdc
+ return_type: locale_t
+ arguments:
+ - type: locale_t
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index e06a4f9b268e66..76a9ed123356a8 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -4,6 +4,7 @@ def StdC : StandardSpec<"stdc"> {
PtrType StructTmPtr = PtrType<StructTmType>;
PtrType TimeTTypePtr = PtrType<TimeTType>;
NamedType ClockT = NamedType<"clock_t">;
+ NamedType LocaleT = NamedType<"locale_t">;
NamedType DivTType = NamedType<"div_t">;
NamedType LDivTType = NamedType<"ldiv_t">;
@@ -1588,6 +1589,61 @@ def StdC : StandardSpec<"stdc"> {
]
>;
+
+ NamedType StructLconv : NamedType<"struct lconv">;
+ PtrType StructLconvPtr : PtrType<StructLconv>;
+
+ HeaderSpec Locale = HeaderSpec<
+ "locale.h",
+ [], // Macros
+ [LocaleT, StructLconv], // Types
+ [], // Enumerations
+ [
+ FunctionSpec<
+ "duplocale",
+ RetValSpec<LocaleT>,
+ [
+ ArgSpec<LocaleT>
+ ]
+ >,
+ FunctionSpec<
+ "freelocale",
+ RetValSpec<VoidType>,
+ [
+ ArgSpec<LocaleT>
+ ]
+ >,
+ FunctionSpec<
+ "localeconv",
+ RetValSpec<StructLconvPtr>,
+ []
+ >,
+ FunctionSpec<
+ "newlocale",
+ RetValSpec<LocaleT>,
+ [
+ ArgSpec<IntType>,
+ ArgSpec<ConstCharPtr>,
+ ArgSpec<LocaleT>
+ ]
+ >,
+ FunctionSpec<
+ "setlocale",
+ RetValSpec<CharPtr>,
+ [
+ ArgSpec<IntType>,
+ ArgSpec<ConstCharPtr>
+ ]
+ >,
+ FunctionSpec<
+ "uselocale",
+ RetValSpec<LocaleT>,
+ [
+ ArgSpec<LocaleT>
+ ]
+ >
+ ] // Functions
+ >;
let Headers = [
Assert,
@@ -1610,5 +1666,6 @@ def StdC : StandardSpec<"stdc"> {
Time,
UChar,
WChar,
+ Locale,
];
}
diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index 9597e2380172b5..d554c12fb1ec89 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -40,3 +40,4 @@ add_subdirectory(signal)
add_subdirectory(spawn)
add_subdirectory(threads)
add_subdirectory(time)
+add_subdirectory(locale)
diff --git a/libc/src/locale/CMakeLists.txt b/libc/src/locale/CMakeLists.txt
new file mode 100644
index 00000000000000..6aaeb2ac31488b
--- /dev/null
+++ b/libc/src/locale/CMakeLists.txt
@@ -0,0 +1,76 @@
+add_object_library(
+ locale
+ SRCS
+ locale.cpp
+ HDRS
+ locale.h
+ DEPENDS
+ libc.include.locale
+)
+
+add_entrypoint_object(
+ localeconv
+ SRCS
+ localeconv.cpp
+ HDRS
+ localeconv.h
+ DEPENDS
+ libc.include.locale
+ CXX_STANDARD
+ 20 # For designated initializers
+)
+
+add_entrypoint_object(
+ newlocale
+ SRCS
+ newlocale.cpp
+ HDRS
+ newlocale.h
+ DEPENDS
+ libc.include.locale
+ .locale
+)
+
+add_entrypoint_object(
+ duplocale
+ SRCS
+ duplocale.cpp
+ HDRS
+ duplocale.h
+ DEPENDS
+ libc.include.locale
+ .locale
+)
+
+add_entrypoint_object(
+ setlocale
+ SRCS
+ setlocale.cpp
+ HDRS
+ setlocale.h
+ DEPENDS
+ libc.include.locale
+ .locale
+)
+
+add_entrypoint_object(
+ uselocale
+ SRCS
+ uselocale.cpp
+ HDRS
+ uselocale.h
+ DEPENDS
+ libc.include.locale
+ .locale
+)
+
+add_entrypoint_object(
+ freelocale
+ SRCS
+ freelocale.cpp
+ HDRS
+ freelocale.h
+ DEPENDS
+ libc.include.locale
+ .locale
+)
diff --git a/libc/src/locale/duplocale.cpp b/libc/src/locale/duplocale.cpp
new file mode 100644
index 00000000000000..d1bd0835121fcd
--- /dev/null
+++ b/libc/src/locale/duplocale.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of duplocale ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/locale/duplocale.h"
+#include "include/llvm-libc-macros/locale-macros.h"
+#include "src/locale/locale.h"
+
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(locale_t, duplocale, (locale_t loc)) { return loc; }
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/locale/duplocale.h b/libc/src/locale/duplocale.h
new file mode 100644
index 00000000000000..a745383860d834
--- /dev/null
+++ b/libc/src/locale/duplocale.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for duplocale ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_LOCALE_DUPLOCALE_H
+#define LLVM_LIBC_SRC_LOCALE_DUPLOCALE_H
+
+#include "src/__support/macros/config.h"
+
+#include "hdr/types/locale_t.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+locale_t duplocale(locale_t loc);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_LOCALE_DUPLOCALE_H
diff --git a/libc/src/locale/freelocale.cpp b/libc/src/locale/freelocale.cpp
new file mode 100644
index 00000000000000..2008995f101bf0
--- /dev/null
+++ b/libc/src/locale/freelocale.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of freelocale --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/locale/freelocale.h"
+#include "include/llvm-libc-macros/locale-macros.h"
+#include "src/locale/locale.h"
+
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(void, freelocale, (locale_t)) {}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/locale/freelocale.h b/libc/src/locale/freelocale.h
new file mode 100644
index 00000000000000..77ece304307383
--- /dev/null
+++ b/libc/src/locale/freelocale.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for freelocale --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_LOCALE_FREELOCALE_H
+#define LLVM_LIBC_SRC_LOCALE_FREELOCALE_H
+
+#include "src/__support/macros/config.h"
+
+#include "hdr/types/locale_t.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+void freelocale(locale_t loc);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_LOCALE_FREELOCALE_H
diff --git a/libc/src/locale/locale.cpp b/libc/src/locale/locale.cpp
new file mode 100644
index 00000000000000..18ebc33ad58234
--- /dev/null
+++ b/libc/src/locale/locale.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of locale ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/locale/locale.h"
+
+#include "include/llvm-libc-macros/locale-macros.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+__locale_t c_locale = {nullptr};
+
+LIBC_THREAD_LOCAL locale_t locale = nullptr;
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/locale/locale.h b/libc/src/locale/locale.h
new file mode 100644
index 00000000000000..6d6db2bcacad3f
--- /dev/null
+++ b/libc/src/locale/locale.h
@@ -0,0 +1,36 @@
+//===-- Implementation header for the locale --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_LOCALE_LOCALECONV_H
+#define LLVM_LIBC_SRC_LOCALE_LOCALECONV_H
+
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+
+#include "hdr/types/locale_t.h"
+
+#include <stddef.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+// We only support the "C" locale right now.
+static constexpr size_t MAX_LOCALE_NAME_SIZE = 2;
+
+struct __locale_data {
+ char name[MAX_LOCALE_NAME_SIZE];
+};
+
+// The pointer to the default "C" locale.
+extern __locale_t c_locale;
+
+// The global locale instance.
+LIBC_THREAD_LOCAL extern locale_t locale;
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_LOCALE_LOCALECONV_H
diff --git a/libc/src/locale/localeconv.cpp b/libc/src/locale/localeconv.cpp
new file mode 100644
index 00000000000000..e4d7536bf1ffb7
--- /dev/null
+++ b/libc/src/locale/localeconv.cpp
@@ -0,0 +1,49 @@
+//===-- Implementation of localeconv --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/locale/localeconv.h"
+
+#include "src/__support/CPP/limits.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+static char DOT_STRING[] = ".";
+static char EMPTY_STRING[] = "";
+
+static struct lconv C_LCONV = {
+ .decimal_point = DOT_STRING,
+ .thousands_sep = EMPTY_STRING,
+ .grouping = EMPTY_STRING,
+ .mon_decimal_point = EMPTY_STRING,
+ .mon_thousands_sep = EMPTY_STRING,
+ .mon_grouping = EMPTY_STRING,
+ .positive_sign = EMPTY_STRING,
+ .negative_sign = EMPTY_STRING,
+ .currency_symbol = EMPTY_STRING,
+ .frac_digits = CHAR_MAX,
+ .p_cs_precedes = CHAR_MAX,
+ .n_cs_precedes = CHAR_MAX,
+ .p_sep_by_space = CHAR_MAX,
+ .n_sep_by_space = CHAR_MAX,
+ .p_sign_posn = CHAR_MAX,
+ .n_sign_posn = CHAR_MAX,
+ .int_curr_symbol = EMPTY_STRING,
+ .int_frac_digits = CHAR_MAX,
+ .int_p_cs_precedes = CHAR_MAX,
+ .int_n_cs_precedes = CHAR_MAX,
+ .int_p_sep_by_space = CHAR_MAX,
+ .int_n_sep_by_space = CHAR_MAX,
+ .int_p_sign_posn = CHAR_MAX,
+ .int_n_sign_posn = CHAR_MAX,
+};
+
+LLVM_LIBC_FUNCTION(struct lconv *, localeconv, ()) { return &C_LCONV; }
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/locale/localeconv.h b/libc/src/locale/localeconv.h
new file mode 100644
index 00000000000000..a8f7599b572bf8
--- /dev/null
+++ b/libc/src/locale/localeconv.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for localeconv --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_LOCALE_LOCALECONV_H
+#define LLVM_LIBC_SRC_LOCALE_LOCALECONV_H
+
+#include "src/__support/macros/config.h"
+
+#include "include/llvm-libc-types/struct_lconv.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+struct lconv *localeconv();
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_LOCALE_LOCALECONV_H
diff --git a/libc/src/locale/newlocale.cpp b/libc/src/locale/newlocale.cpp
new file mode 100644
index 00000000000000..379e7e6385d09f
--- /dev/null
+++ b/libc/src/locale/newlocale.cpp
@@ -0,0 +1,28 @@
+//===-- Implementation of newlocale ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/locale/newlocale.h"
+#include "include/llvm-libc-macros/locale-macros.h"
+#include "src/locale/locale.h"
+
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(locale_t, newlocale,
+ (int category_mask, const char *locale_name, locale_t)) {
+ cpp::string_view name(locale_name);
+ if (category_mask > LC_ALL || (!name.empty() && name != "C"))
+ return nullptr;
+
+ return &c_locale;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/locale/newlocale.h b/libc/src/locale/newlocale.h
new file mode 100644
index 00000000000000..08a0071cb7aeaa
--- /dev/null
+++ b/libc/src/locale/newlocale.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for setlocale ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_LOCALE_SETLOCALE_H
+#define LLVM_LIBC_SRC_LOCALE_SETLOCALE_H
+
+#include "src/__support/macros/config.h"
+
+#include "hdr/types/locale_t.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+locale_t newlocale(int category_mask, const char *locale_name, locale_t base);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_LOCALE_SETLOCALE_H
diff --git a/libc/src/locale/setlocale.cpp b/libc/src/locale/setlocale.cpp
new file mode 100644
index 00000000000000..0950ad73cbe2cf
--- /dev/null
+++ b/libc/src/locale/setlocale.cpp
@@ -0,0 +1,28 @@
+//===-- Implementation of setlocale ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/locale/setlocale.h"
+#include "include/llvm-libc-macros/locale-macros.h"
+#include "src/locale/locale.h"
+
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(char *, setlocale, (int category, const char *locale_name)) {
+ cpp::string_view name(locale_name);
+ if (category > LC_ALL || (!name.empty() && name != "C"))
+ return nullptr;
+
+ static char locale_str[] = "C";
+ return locale_str;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/locale/setlocale.h b/libc/src/locale/setlocale.h
new file mode 100644
index 00000000000000..a9213cf409a7b6
--- /dev/null
+++ b/libc/src/locale/setlocale.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for setlocale ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_LOCALE_SETLOCALE_H
+#define LLVM_LIBC_SRC_LOCALE_SETLOCALE_H
+
+#include "src/__support/macros/config.h"
+
+#include "hdr/types/locale_t.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+char *setlocale(int category, const char *locale_name);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_LOCALE_SETLOCALE_H
diff --git a/libc/src/locale/uselocale.cpp b/libc/src/locale/uselocale.cpp
new file mode 100644
index 00000000000000..d6fdad248f12b2
--- /dev/null
+++ b/libc/src/locale/uselocale.cpp
@@ -0,0 +1,23 @@
+//===-- Implementation of uselocale ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/locale/uselocale.h"
+#include "src/locale/locale.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(locale_t, uselocale, (locale_t newloc)) {
+ if (!newloc)
+ return locale;
+ return locale = newloc;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/locale/uselocale.h b/libc/src/locale/uselocale.h
new file mode 100644
index 00000000000000..15403490d2f8cc
--- /dev/null
+++ b/libc/src/locale/uselocale.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for uselocale ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_LOCALE_USELOCALE_H
+#define LLVM_LIBC_SRC_LOCALE_USELOCALE_H
+
+#include "src/__support/macros/config.h"
+
+#include "hdr/types/locale_t.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+locale_t uselocale(locale_t newloc);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_LOCALE_USELOCALE_H
diff --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt
index 60ea7e6a90d715..ddc6a5c7f6965f 100644
--- a/libc/test/src/CMakeLists.txt
+++ b/libc/test/src/CMakeLists.txt
@@ -82,6 +82,7 @@ add_subdirectory(setjmp)
add_subdirectory(signal)
add_subdirectory(spawn)
add_subdirectory(time)
+add_subdirectory(locale)
if(${LIBC_TARGET_OS} STREQUAL "linux")
add_subdirectory(pthread)
diff --git a/libc/test/src/locale/CMakeLists.txt b/libc/test/src/locale/CMakeLists.txt
new file mode 100644
index 00000000000000..3192004db26dd6
--- /dev/null
+++ b/libc/test/src/locale/CMakeLists.txt
@@ -0,0 +1,25 @@
+add_custom_target(libc-locale-tests)
+
+add_libc_test(
+ locale_test
+ SUITE
+ libc-locale-tests
+ SRCS
+ locale_test.cpp
+ DEPENDS
+ libc.include.locale
+ libc.src.locale.newlocale
+ libc.src.locale.uselocale
+ libc.src.locale.freelocale
+)
+
+add_libc_test(
+ localeconv_test
+ SUITE
+ libc-locale-tests
+ SRCS
+ localeconv_test.cpp
+ DEPENDS
+ libc.include.locale
+ libc.src.locale.localeconv
+)
diff --git a/libc/test/src/locale/locale_test.cpp b/libc/test/src/locale/locale_test.cpp
new file mode 100644
index 00000000000000..bc48bb851f4e4c
--- /dev/null
+++ b/libc/test/src/locale/locale_test.cpp
@@ -0,0 +1,27 @@
+//===-- Unittests for locale ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/locale/freelocale.h"
+#include "src/locale/newlocale.h"
+#include "src/locale/uselocale.h"
+
+#include "test/UnitTest/Test.h"
+
+#include "include/llvm-libc-macros/locale-macros.h"
+
+TEST(LlvmLibcLocale, DefaultLocale) {
+ locale_t new_locale = LIBC_NAMESPACE::newlocale(LC_ALL, "C", nullptr);
+ EXPECT_NE(new_locale, static_cast<locale_t>(nullptr));
+
+ locale_t old_locale = LIBC_NAMESPACE::uselocale(new_locale);
+ EXPECT_NE(old_locale, static_cast<locale_t>(nullptr));
+
+ LIBC_NAMESPACE::freelocale(new_locale);
+
+ LIBC_NAMESPACE::uselocale(old_locale);
+}
diff --git a/libc/test/src/locale/localeconv_test.cpp b/libc/test/src/locale/localeconv_test.cpp
new file mode 100644
index 00000000000000..79264276dec354
--- /dev/null
+++ b/libc/test/src/locale/localeconv_test.cpp
@@ -0,0 +1,17 @@
+//===-- Unittests for localeconv ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "include/llvm-libc-macros/locale-macros.h"
+#include "src/locale/localeconv.h"
+
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcLocale, DefaultLocale) {
+ struct lconv *conv = LIBC_NAMESPACE::localeconv();
+ EXPECT_STREQ(conv->decimal_point, ".");
+}
>From de606a377bf37efd372f04509c824a32910bacdb Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Fri, 9 Aug 2024 21:27:28 -0500
Subject: [PATCH 2/2] [libc] Add `ctype.h` locale variants
Summary:
This patch adds all the libc ctype variants. These ignore the locale
ingormation completely, so they're pretty much just stubs. Because these
use locale information, which is system scope, we do not enable building
them outisde of full build mode.
---
libc/config/gpu/entrypoints.txt | 14 ++
libc/config/linux/x86_64/entrypoints.txt | 16 +++
libc/include/CMakeLists.txt | 1 +
libc/newhdrgen/yaml/ctype.yaml | 102 ++++++++++++++-
libc/spec/stdc.td | 74 ++++++++++-
libc/src/ctype/CMakeLists.txt | 156 +++++++++++++++++++++++
libc/src/ctype/isalnum.cpp | 2 -
libc/src/ctype/isalnum_l.cpp | 21 +++
libc/src/ctype/isalnum_l.h | 21 +++
libc/src/ctype/isalpha.cpp | 2 -
libc/src/ctype/isalpha_l.cpp | 21 +++
libc/src/ctype/isalpha_l.h | 21 +++
libc/src/ctype/isblank.cpp | 2 -
libc/src/ctype/isblank_l.cpp | 20 +++
libc/src/ctype/isblank_l.h | 21 +++
libc/src/ctype/iscntrl.cpp | 2 -
libc/src/ctype/iscntrl_l.cpp | 21 +++
libc/src/ctype/iscntrl_l.h | 21 +++
libc/src/ctype/isdigit.cpp | 2 -
libc/src/ctype/isdigit_l.cpp | 20 +++
libc/src/ctype/isdigit_l.h | 21 +++
libc/src/ctype/isgraph.cpp | 2 -
libc/src/ctype/isgraph_l.cpp | 21 +++
libc/src/ctype/isgraph_l.h | 21 +++
libc/src/ctype/islower.cpp | 2 -
libc/src/ctype/islower_l.cpp | 21 +++
libc/src/ctype/islower_l.h | 21 +++
libc/src/ctype/isprint.cpp | 2 -
libc/src/ctype/isprint_l.cpp | 21 +++
libc/src/ctype/isprint_l.h | 21 +++
libc/src/ctype/ispunct.cpp | 2 -
libc/src/ctype/ispunct_l.cpp | 22 ++++
libc/src/ctype/ispunct_l.h | 21 +++
libc/src/ctype/isspace.cpp | 2 -
libc/src/ctype/isspace_l.cpp | 21 +++
libc/src/ctype/isspace_l.h | 21 +++
libc/src/ctype/isupper.cpp | 2 -
libc/src/ctype/isupper_l.cpp | 21 +++
libc/src/ctype/isupper_l.h | 21 +++
libc/src/ctype/isxdigit.cpp | 2 -
libc/src/ctype/isxdigit_l.cpp | 22 ++++
libc/src/ctype/isxdigit_l.h | 21 +++
libc/src/ctype/tolower.cpp | 2 -
libc/src/ctype/tolower_l.cpp | 21 +++
libc/src/ctype/tolower_l.h | 21 +++
libc/src/ctype/toupper.cpp | 2 -
libc/src/ctype/toupper_l.cpp | 23 ++++
libc/src/ctype/toupper_l.h | 21 +++
48 files changed, 950 insertions(+), 31 deletions(-)
create mode 100644 libc/src/ctype/isalnum_l.cpp
create mode 100644 libc/src/ctype/isalnum_l.h
create mode 100644 libc/src/ctype/isalpha_l.cpp
create mode 100644 libc/src/ctype/isalpha_l.h
create mode 100644 libc/src/ctype/isblank_l.cpp
create mode 100644 libc/src/ctype/isblank_l.h
create mode 100644 libc/src/ctype/iscntrl_l.cpp
create mode 100644 libc/src/ctype/iscntrl_l.h
create mode 100644 libc/src/ctype/isdigit_l.cpp
create mode 100644 libc/src/ctype/isdigit_l.h
create mode 100644 libc/src/ctype/isgraph_l.cpp
create mode 100644 libc/src/ctype/isgraph_l.h
create mode 100644 libc/src/ctype/islower_l.cpp
create mode 100644 libc/src/ctype/islower_l.h
create mode 100644 libc/src/ctype/isprint_l.cpp
create mode 100644 libc/src/ctype/isprint_l.h
create mode 100644 libc/src/ctype/ispunct_l.cpp
create mode 100644 libc/src/ctype/ispunct_l.h
create mode 100644 libc/src/ctype/isspace_l.cpp
create mode 100644 libc/src/ctype/isspace_l.h
create mode 100644 libc/src/ctype/isupper_l.cpp
create mode 100644 libc/src/ctype/isupper_l.h
create mode 100644 libc/src/ctype/isxdigit_l.cpp
create mode 100644 libc/src/ctype/isxdigit_l.h
create mode 100644 libc/src/ctype/tolower_l.cpp
create mode 100644 libc/src/ctype/tolower_l.h
create mode 100644 libc/src/ctype/toupper_l.cpp
create mode 100644 libc/src/ctype/toupper_l.h
diff --git a/libc/config/gpu/entrypoints.txt b/libc/config/gpu/entrypoints.txt
index 592c8cdb7ae778..9a4e7f3443beb1 100644
--- a/libc/config/gpu/entrypoints.txt
+++ b/libc/config/gpu/entrypoints.txt
@@ -4,21 +4,35 @@ set(TARGET_LIBC_ENTRYPOINTS
# ctype.h entrypoints
libc.src.ctype.isalnum
+ libc.src.ctype.isalnum_l
libc.src.ctype.isalpha
+ libc.src.ctype.isalpha_l
libc.src.ctype.isascii
libc.src.ctype.isblank
+ libc.src.ctype.isblank_l
libc.src.ctype.iscntrl
+ libc.src.ctype.iscntrl_l
libc.src.ctype.isdigit
+ libc.src.ctype.isdigit_l
libc.src.ctype.isgraph
+ libc.src.ctype.isgraph_l
libc.src.ctype.islower
+ libc.src.ctype.islower_l
libc.src.ctype.isprint
+ libc.src.ctype.isprint_l
libc.src.ctype.ispunct
+ libc.src.ctype.ispunct_l
libc.src.ctype.isspace
+ libc.src.ctype.isspace_l
libc.src.ctype.isupper
+ libc.src.ctype.isupper_l
libc.src.ctype.isxdigit
+ libc.src.ctype.isxdigit_l
libc.src.ctype.toascii
libc.src.ctype.tolower
+ libc.src.ctype.tolower_l
libc.src.ctype.toupper
+ libc.src.ctype.toupper_l
# string.h entrypoints
libc.src.string.bcmp
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index e7c3c7db64abe5..bac1e3cfa85da7 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -782,6 +782,22 @@ endif()
if(LLVM_LIBC_FULL_BUILD)
list(APPEND TARGET_LIBC_ENTRYPOINTS
+ # ctype.h entrypoints
+ libc.src.ctype.isalnum_l
+ libc.src.ctype.isalpha_l
+ libc.src.ctype.isblank_l
+ libc.src.ctype.iscntrl_l
+ libc.src.ctype.isdigit_l
+ libc.src.ctype.isgraph_l
+ libc.src.ctype.islower_l
+ libc.src.ctype.isprint_l
+ libc.src.ctype.ispunct_l
+ libc.src.ctype.isspace_l
+ libc.src.ctype.isupper_l
+ libc.src.ctype.isxdigit_l
+ libc.src.ctype.tolower_l
+ libc.src.ctype.toupper_l
+
# assert.h entrypoints
libc.src.assert.__assert_fail
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 733582c182735e..8c0b2a2b1c574d 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -45,6 +45,7 @@ add_header_macro(
ctype.h
DEPENDS
.llvm_libc_common_h
+ .llvm-libc-types.locale_t
)
add_header_macro(
diff --git a/libc/newhdrgen/yaml/ctype.yaml b/libc/newhdrgen/yaml/ctype.yaml
index f3108a34d43377..b4823c3e53234a 100644
--- a/libc/newhdrgen/yaml/ctype.yaml
+++ b/libc/newhdrgen/yaml/ctype.yaml
@@ -1,6 +1,7 @@
header: ctype.h
macros: []
-types: []
+types:
+ - type_name: locale_t
enums: []
objects: []
functions:
@@ -100,4 +101,101 @@ functions:
return_type: int
arguments:
- type: int
- functions: null
+ - name: isalnum_l
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: int
+ - type: locale_t
+ - name: isalpha_l
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: int
+ - type: locale_t
+ - name: isblank_l
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: int
+ - type: locale_t
+ - name: iscntrl_l
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: int
+ - type: locale_t
+ - name: isdigit_l
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: int
+ - type: locale_t
+ - name: isgraph_l
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: int
+ - type: locale_t
+ - name: islower_l
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: int
+ - type: locale_t
+ - name: isprint_l
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: int
+ - type: locale_t
+ - name: ispunct_l
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: int
+ - type: locale_t
+ - name: isspace_l
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: int
+ - type: locale_t
+ - name: isupper_l
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: int
+ - type: locale_t
+ - name: isxdigit_l
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: int
+ - type: locale_t
+ - name: tolower_l
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: int
+ - type: locale_t
+ - name: toupper_l
+ standards:
+ - stdc
+ return_type: int
+ arguments:
+ - type: int
+ - type: locale_t
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 76a9ed123356a8..6fd3e6d861848b 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -35,7 +35,9 @@ def StdC : StandardSpec<"stdc"> {
HeaderSpec CType = HeaderSpec<
"ctype.h",
[], // Macros
- [], // Types
+ [
+ LocaleT
+ ], // Types
[], // Enumerations
[
FunctionSpec<
@@ -108,6 +110,76 @@ def StdC : StandardSpec<"stdc"> {
RetValSpec<IntType>,
[ArgSpec<IntType>]
>,
+ FunctionSpec<
+ "isalnum_l",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>, ArgSpec<LocaleT>]
+ >,
+ FunctionSpec<
+ "isalpha_l",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>, ArgSpec<LocaleT>]
+ >,
+ FunctionSpec<
+ "isblank_l",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>, ArgSpec<LocaleT>]
+ >,
+ FunctionSpec<
+ "iscntrl_l",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>, ArgSpec<LocaleT>]
+ >,
+ FunctionSpec<
+ "isdigit_l",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>, ArgSpec<LocaleT>]
+ >,
+ FunctionSpec<
+ "isgraph_l",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>, ArgSpec<LocaleT>]
+ >,
+ FunctionSpec<
+ "islower_l",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>, ArgSpec<LocaleT>]
+ >,
+ FunctionSpec<
+ "isprint_l",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>, ArgSpec<LocaleT>]
+ >,
+ FunctionSpec<
+ "ispunct_l",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>, ArgSpec<LocaleT>]
+ >,
+ FunctionSpec<
+ "isspace_l",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>, ArgSpec<LocaleT>]
+ >,
+ FunctionSpec<
+ "isupper_l",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>, ArgSpec<LocaleT>]
+ >,
+ FunctionSpec<
+ "isxdigit_l",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>, ArgSpec<LocaleT>]
+ >,
+ FunctionSpec<
+ "tolower_l",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>, ArgSpec<LocaleT>]
+ >,
+ FunctionSpec<
+ "toupper_l",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>, ArgSpec<LocaleT>]
+ >,
]
>;
diff --git a/libc/src/ctype/CMakeLists.txt b/libc/src/ctype/CMakeLists.txt
index ae4eec9615dc19..8830c1bccf9eaa 100644
--- a/libc/src/ctype/CMakeLists.txt
+++ b/libc/src/ctype/CMakeLists.txt
@@ -146,3 +146,159 @@ add_entrypoint_object(
DEPENDS
libc.src.__support.ctype_utils
)
+
+# Do not build the locale versions in overlay mode.
+if(NOT LLVM_LIBC_FULL_BUILD)
+ return()
+endif()
+
+add_entrypoint_object(
+ isalnum_l
+ SRCS
+ isalnum_l.cpp
+ HDRS
+ isalnum_l.h
+ DEPENDS
+ libc.include.ctype
+ libc.src.__support.ctype_utils
+ libc.hdr.types.locale_t
+)
+
+add_entrypoint_object(
+ isalpha_l
+ SRCS
+ isalpha_l.cpp
+ HDRS
+ isalpha_l.h
+ DEPENDS
+ libc.src.__support.ctype_utils
+ libc.hdr.types.locale_t
+)
+
+add_entrypoint_object(
+ isblank_l
+ SRCS
+ isblank_l.cpp
+ HDRS
+ isblank_l.h
+ DEPENDS
+ libc.hdr.types.locale_t
+)
+
+add_entrypoint_object(
+ iscntrl_l
+ SRCS
+ iscntrl_l.cpp
+ HDRS
+ iscntrl_l.h
+ DEPENDS
+ libc.hdr.types.locale_t
+)
+
+add_entrypoint_object(
+ isdigit_l
+ SRCS
+ isdigit_l.cpp
+ HDRS
+ isdigit_l.h
+ DEPENDS
+ libc.src.__support.ctype_utils
+ libc.hdr.types.locale_t
+)
+
+add_entrypoint_object(
+ isgraph_l
+ SRCS
+ isgraph_l.cpp
+ HDRS
+ isgraph_l.h
+ DEPENDS
+ libc.src.__support.ctype_utils
+ libc.hdr.types.locale_t
+)
+
+add_entrypoint_object(
+ islower_l
+ SRCS
+ islower_l.cpp
+ HDRS
+ islower_l.h
+ DEPENDS
+ libc.src.__support.ctype_utils
+ libc.hdr.types.locale_t
+)
+
+add_entrypoint_object(
+ isprint_l
+ SRCS
+ isprint_l.cpp
+ HDRS
+ isprint_l.h
+ DEPENDS
+ libc.hdr.types.locale_t
+)
+
+add_entrypoint_object(
+ ispunct_l
+ SRCS
+ ispunct_l.cpp
+ HDRS
+ ispunct_l.h
+ DEPENDS
+ libc.src.__support.ctype_utils
+ libc.hdr.types.locale_t
+)
+
+add_entrypoint_object(
+ isspace_l
+ SRCS
+ isspace_l.cpp
+ HDRS
+ isspace_l.h
+ DEPENDS
+ libc.hdr.types.locale_t
+)
+
+add_entrypoint_object(
+ isupper_l
+ SRCS
+ isupper_l.cpp
+ HDRS
+ isupper_l.h
+ DEPENDS
+ libc.src.__support.ctype_utils
+ libc.hdr.types.locale_t
+)
+
+add_entrypoint_object(
+ isxdigit_l
+ SRCS
+ isxdigit_l.cpp
+ HDRS
+ isxdigit_l.h
+ DEPENDS
+ libc.src.__support.ctype_utils
+ libc.hdr.types.locale_t
+)
+
+add_entrypoint_object(
+ tolower_l
+ SRCS
+ tolower_l.cpp
+ HDRS
+ tolower_l.h
+ DEPENDS
+ libc.src.__support.ctype_utils
+ libc.hdr.types.locale_t
+)
+
+add_entrypoint_object(
+ toupper_l
+ SRCS
+ toupper_l.cpp
+ HDRS
+ toupper_l.h
+ DEPENDS
+ libc.src.__support.ctype_utils
+ libc.hdr.types.locale_t
+)
diff --git a/libc/src/ctype/isalnum.cpp b/libc/src/ctype/isalnum.cpp
index 382553c23a6bfb..54a3e357488790 100644
--- a/libc/src/ctype/isalnum.cpp
+++ b/libc/src/ctype/isalnum.cpp
@@ -14,8 +14,6 @@
namespace LIBC_NAMESPACE_DECL {
-// TODO: Currently restricted to default locale.
-// These should be extended using locale information.
LLVM_LIBC_FUNCTION(int, isalnum, (int c)) {
return static_cast<int>(internal::isalnum(static_cast<unsigned>(c)));
}
diff --git a/libc/src/ctype/isalnum_l.cpp b/libc/src/ctype/isalnum_l.cpp
new file mode 100644
index 00000000000000..671d9b75c4c33a
--- /dev/null
+++ b/libc/src/ctype/isalnum_l.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of isalnum -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/isalnum_l.h"
+#include "src/__support/ctype_utils.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, isalnum_l, (int c, locale_t)) {
+ return static_cast<int>(internal::isalnum(static_cast<unsigned>(c)));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isalnum_l.h b/libc/src/ctype/isalnum_l.h
new file mode 100644
index 00000000000000..5bc892e6c8747e
--- /dev/null
+++ b/libc/src/ctype/isalnum_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for isalnum_l -----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_ISALNUM_H
+#define LLVM_LIBC_SRC_CTYPE_ISALNUM_H
+
+#include "hdr/types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int isalnum_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_CTYPE_ISALNUM_H
diff --git a/libc/src/ctype/isalpha.cpp b/libc/src/ctype/isalpha.cpp
index 1a63406780b6e0..78b26f6a486eae 100644
--- a/libc/src/ctype/isalpha.cpp
+++ b/libc/src/ctype/isalpha.cpp
@@ -14,8 +14,6 @@
namespace LIBC_NAMESPACE_DECL {
-// TODO: Currently restricted to default locale.
-// These should be extended using locale information.
LLVM_LIBC_FUNCTION(int, isalpha, (int c)) {
return static_cast<int>(internal::isalpha(static_cast<unsigned>(c)));
}
diff --git a/libc/src/ctype/isalpha_l.cpp b/libc/src/ctype/isalpha_l.cpp
new file mode 100644
index 00000000000000..0619d979bedf22
--- /dev/null
+++ b/libc/src/ctype/isalpha_l.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of isalpha -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/isalpha_l.h"
+
+#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, isalpha_l, (int c, locale_t)) {
+ return static_cast<int>(internal::isalpha(static_cast<unsigned>(c)));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isalpha_l.h b/libc/src/ctype/isalpha_l.h
new file mode 100644
index 00000000000000..3591f1175cb9a9
--- /dev/null
+++ b/libc/src/ctype/isalpha_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for isalpha_l -----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_ISALPHA_H
+#define LLVM_LIBC_SRC_CTYPE_ISALPHA_H
+
+#include "hdr/types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int isalpha_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_CTYPE_ISALPHA_H
diff --git a/libc/src/ctype/isblank.cpp b/libc/src/ctype/isblank.cpp
index a4f33d265bd2dd..e0a20829f86cee 100644
--- a/libc/src/ctype/isblank.cpp
+++ b/libc/src/ctype/isblank.cpp
@@ -13,8 +13,6 @@
namespace LIBC_NAMESPACE_DECL {
-// TODO: Currently restricted to default locale.
-// These should be extended using locale information.
LLVM_LIBC_FUNCTION(int, isblank, (int c)) {
return static_cast<int>(c == ' ' || c == '\t');
}
diff --git a/libc/src/ctype/isblank_l.cpp b/libc/src/ctype/isblank_l.cpp
new file mode 100644
index 00000000000000..4f6b0bfac29724
--- /dev/null
+++ b/libc/src/ctype/isblank_l.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of isblank -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/isblank_l.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, isblank_l, (int c, locale_t)) {
+ return static_cast<int>(c == ' ' || c == '\t');
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isblank_l.h b/libc/src/ctype/isblank_l.h
new file mode 100644
index 00000000000000..61ede30ae76775
--- /dev/null
+++ b/libc/src/ctype/isblank_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for isblank_l -----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_ISBLANK_H
+#define LLVM_LIBC_SRC_CTYPE_ISBLANK_H
+
+#include "hdr/types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int isblank_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_CTYPE_ISBLANK_H
diff --git a/libc/src/ctype/iscntrl.cpp b/libc/src/ctype/iscntrl.cpp
index fb582fd6ef0820..2218adfcc33f3b 100644
--- a/libc/src/ctype/iscntrl.cpp
+++ b/libc/src/ctype/iscntrl.cpp
@@ -13,8 +13,6 @@
namespace LIBC_NAMESPACE_DECL {
-// TODO: Currently restricted to default locale.
-// These should be extended using locale information.
LLVM_LIBC_FUNCTION(int, iscntrl, (int c)) {
const unsigned ch = static_cast<unsigned>(c);
return static_cast<int>(ch < 0x20 || ch == 0x7f);
diff --git a/libc/src/ctype/iscntrl_l.cpp b/libc/src/ctype/iscntrl_l.cpp
new file mode 100644
index 00000000000000..83aa480299fadc
--- /dev/null
+++ b/libc/src/ctype/iscntrl_l.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of iscntrl -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/iscntrl_l.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, iscntrl_l, (int c, locale_t)) {
+ const unsigned ch = static_cast<unsigned>(c);
+ return static_cast<int>(ch < 0x20 || ch == 0x7f);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/iscntrl_l.h b/libc/src/ctype/iscntrl_l.h
new file mode 100644
index 00000000000000..7dee44fcd0bebc
--- /dev/null
+++ b/libc/src/ctype/iscntrl_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for iscntrl_l -----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_ISCNTRL_H
+#define LLVM_LIBC_SRC_CTYPE_ISCNTRL_H
+
+#include "hdr/types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int iscntrl_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_CTYPE_ISCNTRL_H
diff --git a/libc/src/ctype/isdigit.cpp b/libc/src/ctype/isdigit.cpp
index 43c5f1940c7f00..1f711943861f8b 100644
--- a/libc/src/ctype/isdigit.cpp
+++ b/libc/src/ctype/isdigit.cpp
@@ -13,8 +13,6 @@
namespace LIBC_NAMESPACE_DECL {
-// TODO: Currently restricted to default locale.
-// These should be extended using locale information.
LLVM_LIBC_FUNCTION(int, isdigit, (int c)) {
return static_cast<int>(internal::isdigit(static_cast<unsigned>(c)));
}
diff --git a/libc/src/ctype/isdigit_l.cpp b/libc/src/ctype/isdigit_l.cpp
new file mode 100644
index 00000000000000..ca981362bfe839
--- /dev/null
+++ b/libc/src/ctype/isdigit_l.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of isdigit -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/isdigit_l.h"
+#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, isdigit_l, (int c, locale_t)) {
+ return static_cast<int>(internal::isdigit(static_cast<unsigned>(c)));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isdigit_l.h b/libc/src/ctype/isdigit_l.h
new file mode 100644
index 00000000000000..abeec3464941a0
--- /dev/null
+++ b/libc/src/ctype/isdigit_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for isdigit_l -----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_ISDIGIT_H
+#define LLVM_LIBC_SRC_CTYPE_ISDIGIT_H
+
+#include "hdr/types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int isdigit_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_CTYPE_ISDIGIT_H
diff --git a/libc/src/ctype/isgraph.cpp b/libc/src/ctype/isgraph.cpp
index a5b6e501b5813f..74bb2e75d138e6 100644
--- a/libc/src/ctype/isgraph.cpp
+++ b/libc/src/ctype/isgraph.cpp
@@ -14,8 +14,6 @@
namespace LIBC_NAMESPACE_DECL {
-// TODO: Currently restricted to default locale.
-// These should be extended using locale information.
LLVM_LIBC_FUNCTION(int, isgraph, (int c)) {
return static_cast<int>(internal::isgraph(static_cast<unsigned>(c)));
}
diff --git a/libc/src/ctype/isgraph_l.cpp b/libc/src/ctype/isgraph_l.cpp
new file mode 100644
index 00000000000000..cbef6df148aed6
--- /dev/null
+++ b/libc/src/ctype/isgraph_l.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of isgraph -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/isgraph_l.h"
+
+#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, isgraph_l, (int c, locale_t)) {
+ return static_cast<int>(internal::isgraph(static_cast<unsigned>(c)));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isgraph_l.h b/libc/src/ctype/isgraph_l.h
new file mode 100644
index 00000000000000..d96a4608655092
--- /dev/null
+++ b/libc/src/ctype/isgraph_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for isgraph_l -----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_ISGRAPH_H
+#define LLVM_LIBC_SRC_CTYPE_ISGRAPH_H
+
+#include "hdr/types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int isgraph_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_CTYPE_ISGRAPH_H
diff --git a/libc/src/ctype/islower.cpp b/libc/src/ctype/islower.cpp
index 61ccbcc1db413b..831aad32d3a22e 100644
--- a/libc/src/ctype/islower.cpp
+++ b/libc/src/ctype/islower.cpp
@@ -14,8 +14,6 @@
namespace LIBC_NAMESPACE_DECL {
-// TODO: Currently restricted to default locale.
-// These should be extended using locale information.
LLVM_LIBC_FUNCTION(int, islower, (int c)) {
return static_cast<int>(internal::islower(static_cast<unsigned>(c)));
}
diff --git a/libc/src/ctype/islower_l.cpp b/libc/src/ctype/islower_l.cpp
new file mode 100644
index 00000000000000..b9be6acc81c992
--- /dev/null
+++ b/libc/src/ctype/islower_l.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of islower -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/islower_l.h"
+#include "src/__support/ctype_utils.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, islower_l, (int c, locale_t)) {
+ return static_cast<int>(internal::islower(static_cast<unsigned>(c)));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/islower_l.h b/libc/src/ctype/islower_l.h
new file mode 100644
index 00000000000000..7d3e2f139602b9
--- /dev/null
+++ b/libc/src/ctype/islower_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for islower_l -----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_ISLOWER_H
+#define LLVM_LIBC_SRC_CTYPE_ISLOWER_H
+
+#include "hdr/types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int islower_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_CTYPE_ISLOWER_H
diff --git a/libc/src/ctype/isprint.cpp b/libc/src/ctype/isprint.cpp
index 42ab9cc8d238a1..349aefe1c17bbd 100644
--- a/libc/src/ctype/isprint.cpp
+++ b/libc/src/ctype/isprint.cpp
@@ -13,8 +13,6 @@
namespace LIBC_NAMESPACE_DECL {
-// TODO: Currently restricted to default locale.
-// These should be extended using locale information.
LLVM_LIBC_FUNCTION(int, isprint, (int c)) {
const unsigned ch = static_cast<unsigned>(c);
return static_cast<int>((ch - ' ') < 95);
diff --git a/libc/src/ctype/isprint_l.cpp b/libc/src/ctype/isprint_l.cpp
new file mode 100644
index 00000000000000..8f51f7f0e3e94b
--- /dev/null
+++ b/libc/src/ctype/isprint_l.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of isprint -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/isprint_l.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, isprint_l, (int c, locale_t)) {
+ const unsigned ch = static_cast<unsigned>(c);
+ return static_cast<int>((ch - ' ') < 95);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isprint_l.h b/libc/src/ctype/isprint_l.h
new file mode 100644
index 00000000000000..bd2ea9354c36a0
--- /dev/null
+++ b/libc/src/ctype/isprint_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for isprint_l -----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_ISPRINT_H
+#define LLVM_LIBC_SRC_CTYPE_ISPRINT_H
+
+#include "hdr/types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int isprint_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_CTYPE_ISPRINT_H
diff --git a/libc/src/ctype/ispunct.cpp b/libc/src/ctype/ispunct.cpp
index c1906e3acdd80e..0635294220b9c3 100644
--- a/libc/src/ctype/ispunct.cpp
+++ b/libc/src/ctype/ispunct.cpp
@@ -14,8 +14,6 @@
namespace LIBC_NAMESPACE_DECL {
-// TODO: Currently restricted to default locale.
-// These should be extended using locale information.
LLVM_LIBC_FUNCTION(int, ispunct, (int c)) {
const unsigned ch = static_cast<unsigned>(c);
return static_cast<int>(!internal::isalnum(ch) && internal::isgraph(ch));
diff --git a/libc/src/ctype/ispunct_l.cpp b/libc/src/ctype/ispunct_l.cpp
new file mode 100644
index 00000000000000..e825fbe2001b08
--- /dev/null
+++ b/libc/src/ctype/ispunct_l.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of ispunct -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/ispunct_l.h"
+
+#include "src/__support/common.h"
+#include "src/__support/ctype_utils.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, ispunct_l, (int c, locale_t)) {
+ const unsigned ch = static_cast<unsigned>(c);
+ return static_cast<int>(!internal::isalnum(ch) && internal::isgraph(ch));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/ispunct_l.h b/libc/src/ctype/ispunct_l.h
new file mode 100644
index 00000000000000..862daf4836f788
--- /dev/null
+++ b/libc/src/ctype/ispunct_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for ispunct_l -----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_ISPUNCT_H
+#define LLVM_LIBC_SRC_CTYPE_ISPUNCT_H
+
+#include "hdr/types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int ispunct_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_CTYPE_ISPUNCT_H
diff --git a/libc/src/ctype/isspace.cpp b/libc/src/ctype/isspace.cpp
index f8908493787841..005bf460fc1032 100644
--- a/libc/src/ctype/isspace.cpp
+++ b/libc/src/ctype/isspace.cpp
@@ -14,8 +14,6 @@
namespace LIBC_NAMESPACE_DECL {
-// TODO: Currently restricted to default locale.
-// These should be extended using locale information.
LLVM_LIBC_FUNCTION(int, isspace, (int c)) {
return static_cast<int>(internal::isspace(static_cast<unsigned>(c)));
}
diff --git a/libc/src/ctype/isspace_l.cpp b/libc/src/ctype/isspace_l.cpp
new file mode 100644
index 00000000000000..5c46dd68051261
--- /dev/null
+++ b/libc/src/ctype/isspace_l.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of isspace -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/isspace_l.h"
+#include "src/__support/ctype_utils.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, isspace_l, (int c, locale_t)) {
+ return static_cast<int>(internal::isspace(static_cast<unsigned>(c)));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isspace_l.h b/libc/src/ctype/isspace_l.h
new file mode 100644
index 00000000000000..61bbf127956da7
--- /dev/null
+++ b/libc/src/ctype/isspace_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for isspace_l -----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_ISSPACE_H
+#define LLVM_LIBC_SRC_CTYPE_ISSPACE_H
+
+#include "hdr/types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int isspace_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_CTYPE_ISSPACE_H
diff --git a/libc/src/ctype/isupper.cpp b/libc/src/ctype/isupper.cpp
index 8f929ea1a009e4..965fa336b28b4d 100644
--- a/libc/src/ctype/isupper.cpp
+++ b/libc/src/ctype/isupper.cpp
@@ -14,8 +14,6 @@
namespace LIBC_NAMESPACE_DECL {
-// TODO: Currently restricted to default locale.
-// These should be extended using locale information.
LLVM_LIBC_FUNCTION(int, isupper, (int c)) {
return static_cast<int>(internal::isupper(static_cast<unsigned>(c)));
}
diff --git a/libc/src/ctype/isupper_l.cpp b/libc/src/ctype/isupper_l.cpp
new file mode 100644
index 00000000000000..358990261d603f
--- /dev/null
+++ b/libc/src/ctype/isupper_l.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of isupper -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/isupper_l.h"
+#include "src/__support/ctype_utils.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, isupper_l, (int c, locale_t)) {
+ return static_cast<int>(internal::isupper(static_cast<unsigned>(c)));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isupper_l.h b/libc/src/ctype/isupper_l.h
new file mode 100644
index 00000000000000..9bee7ef8c09f59
--- /dev/null
+++ b/libc/src/ctype/isupper_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for isupper_l -----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_ISUPPER_H
+#define LLVM_LIBC_SRC_CTYPE_ISUPPER_H
+
+#include "hdr/types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int isupper_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_CTYPE_ISUPPER_H
diff --git a/libc/src/ctype/isxdigit.cpp b/libc/src/ctype/isxdigit.cpp
index 391c5c53cee1e1..6b730c354db083 100644
--- a/libc/src/ctype/isxdigit.cpp
+++ b/libc/src/ctype/isxdigit.cpp
@@ -14,8 +14,6 @@
namespace LIBC_NAMESPACE_DECL {
-// TODO: Currently restricted to default locale.
-// These should be extended using locale information.
LLVM_LIBC_FUNCTION(int, isxdigit, (int c)) {
const unsigned ch = static_cast<unsigned>(c);
return static_cast<int>(internal::isdigit(ch) || (ch | 32) - 'a' < 6);
diff --git a/libc/src/ctype/isxdigit_l.cpp b/libc/src/ctype/isxdigit_l.cpp
new file mode 100644
index 00000000000000..8a5c7d4d28ab1c
--- /dev/null
+++ b/libc/src/ctype/isxdigit_l.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of isxdigit ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/isxdigit_l.h"
+#include "src/__support/ctype_utils.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, isxdigit_l, (int c, locale_t)) {
+ const unsigned ch = static_cast<unsigned>(c);
+ return static_cast<int>(internal::isdigit(ch) || (ch | 32) - 'a' < 6);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/isxdigit_l.h b/libc/src/ctype/isxdigit_l.h
new file mode 100644
index 00000000000000..ee847eda4eae9a
--- /dev/null
+++ b/libc/src/ctype/isxdigit_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for isxdigit_l ----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_ISXDIGIT_H
+#define LLVM_LIBC_SRC_CTYPE_ISXDIGIT_H
+
+#include "hdr/types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int isxdigit_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_CTYPE_ISXDIGIT_H
diff --git a/libc/src/ctype/tolower.cpp b/libc/src/ctype/tolower.cpp
index e230428eef2b14..3ecad7bc5d5d54 100644
--- a/libc/src/ctype/tolower.cpp
+++ b/libc/src/ctype/tolower.cpp
@@ -14,8 +14,6 @@
namespace LIBC_NAMESPACE_DECL {
-// TODO: Currently restricted to default locale.
-// These should be extended using locale information.
LLVM_LIBC_FUNCTION(int, tolower, (int c)) { return internal::tolower(c); }
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/tolower_l.cpp b/libc/src/ctype/tolower_l.cpp
new file mode 100644
index 00000000000000..7ccf31617e5925
--- /dev/null
+++ b/libc/src/ctype/tolower_l.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of tolower -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/tolower_l.h"
+#include "src/__support/ctype_utils.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, tolower_l, (int c, locale_t)) {
+ return internal::tolower(c);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/tolower_l.h b/libc/src/ctype/tolower_l.h
new file mode 100644
index 00000000000000..6099b8c813469c
--- /dev/null
+++ b/libc/src/ctype/tolower_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for tolower_l -----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_TOLOWER_H
+#define LLVM_LIBC_SRC_CTYPE_TOLOWER_H
+
+#include "hdr/types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int tolower_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_CTYPE_TOLOWER_H
diff --git a/libc/src/ctype/toupper.cpp b/libc/src/ctype/toupper.cpp
index 97c1ac2c02b8c0..b5a23fc7f588bd 100644
--- a/libc/src/ctype/toupper.cpp
+++ b/libc/src/ctype/toupper.cpp
@@ -14,8 +14,6 @@
namespace LIBC_NAMESPACE_DECL {
-// TODO: Currently restricted to default locale.
-// These should be extended using locale information.
LLVM_LIBC_FUNCTION(int, toupper, (int c)) {
if (internal::islower(c))
return c - ('a' - 'A');
diff --git a/libc/src/ctype/toupper_l.cpp b/libc/src/ctype/toupper_l.cpp
new file mode 100644
index 00000000000000..f536ff36236160
--- /dev/null
+++ b/libc/src/ctype/toupper_l.cpp
@@ -0,0 +1,23 @@
+//===-- Implementation of toupper_l ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/ctype/toupper_l.h"
+#include "src/__support/ctype_utils.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, toupper_l, (int c, locale_t)) {
+ if (internal::islower(c))
+ return c - ('a' - 'A');
+ return c;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/ctype/toupper_l.h b/libc/src/ctype/toupper_l.h
new file mode 100644
index 00000000000000..8877c35d492bd8
--- /dev/null
+++ b/libc/src/ctype/toupper_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for toupper_l -----------------------*-C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_CTYPE_TOUPPER_H
+#define LLVM_LIBC_SRC_CTYPE_TOUPPER_H
+
+#include "hdr/types/locale_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int toupper_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_CTYPE_TOUPPER_H
More information about the libc-commits
mailing list