[libc-commits] [libc] [libc] Add `locale.h` and related stubs (PR #97494)

Izaak Schroeder via libc-commits libc-commits at lists.llvm.org
Tue Jul 2 17:32:09 PDT 2024


https://github.com/izaakschroeder updated https://github.com/llvm/llvm-project/pull/97494

>From 8f5fdeed0cc2768a675a124ab4626bb628597ac3 Mon Sep 17 00:00:00 2001
From: Izaak Schroeder <izaak.schroeder at gmail.com>
Date: Tue, 2 Jul 2024 11:21:32 -0700
Subject: [PATCH] [libc] Add `locale.h` and related stubs

---
 libc/config/linux/aarch64/entrypoints.txt     | 27 +++++++
 libc/config/linux/aarch64/headers.txt         |  2 +
 libc/config/linux/api.td                      |  7 ++
 libc/config/linux/x86_64/entrypoints.txt      | 27 +++++++
 libc/config/linux/x86_64/headers.txt          |  2 +
 libc/include/CMakeLists.txt                   | 13 ++++
 libc/include/ctype.h.def                      |  1 +
 libc/include/llvm-libc-macros/CMakeLists.txt  |  6 ++
 libc/include/llvm-libc-macros/locale-macros.h | 30 ++++++++
 libc/include/llvm-libc-macros/stdlib-macros.h |  4 +
 libc/include/llvm-libc-types/CMakeLists.txt   |  2 +
 libc/include/llvm-libc-types/locale_t.h       | 18 +++++
 libc/include/llvm-libc-types/struct_lconv.h   | 39 ++++++++++
 libc/include/locale.h.def                     | 18 +++++
 libc/include/stdlib.h.def                     |  1 +
 libc/include/time.h.def                       |  2 +
 libc/spec/posix.td                            | 57 +++++++++++++++
 libc/spec/stdc.td                             | 57 ++++++++++++++-
 libc/src/CMakeLists.txt                       |  1 +
 libc/src/ctype/CMakeLists.txt                 | 73 +++++++++++++++++++
 libc/src/ctype/isdigit_l.cpp                  | 17 +++++
 libc/src/ctype/isdigit_l.h                    | 20 +++++
 libc/src/ctype/islower_l.cpp                  | 20 +++++
 libc/src/ctype/islower_l.h                    | 20 +++++
 libc/src/ctype/isupper_l.cpp                  | 20 +++++
 libc/src/ctype/isupper_l.h                    | 20 +++++
 libc/src/ctype/isxdigit_l.cpp                 | 21 ++++++
 libc/src/ctype/isxdigit_l.h                   | 20 +++++
 libc/src/ctype/tolower_l.cpp                  | 20 +++++
 libc/src/ctype/tolower_l.h                    | 20 +++++
 libc/src/ctype/toupper_l.cpp                  | 21 ++++++
 libc/src/ctype/toupper_l.h                    | 20 +++++
 libc/src/locale/CMakeLists.txt                | 60 +++++++++++++++
 libc/src/locale/duplocale.cpp                 | 16 ++++
 libc/src/locale/duplocale.h                   | 20 +++++
 libc/src/locale/freelocale.cpp                | 18 +++++
 libc/src/locale/freelocale.h                  | 20 +++++
 libc/src/locale/localeconv.cpp                | 46 ++++++++++++
 libc/src/locale/localeconv.h                  | 20 +++++
 libc/src/locale/newlocale.cpp                 | 18 +++++
 libc/src/locale/newlocale.h                   | 20 +++++
 libc/src/locale/setlocale.cpp                 | 18 +++++
 libc/src/locale/setlocale.h                   | 18 +++++
 libc/src/locale/uselocale.cpp                 | 16 ++++
 libc/src/locale/uselocale.h                   | 20 +++++
 libc/src/stdlib/CMakeLists.txt                | 60 +++++++++++++++
 libc/src/stdlib/strtod_l.cpp                  | 22 ++++++
 libc/src/stdlib/strtod_l.h                    | 22 ++++++
 libc/src/stdlib/strtof_l.cpp                  | 22 ++++++
 libc/src/stdlib/strtof_l.h                    | 22 ++++++
 libc/src/stdlib/strtold_l.cpp                 | 22 ++++++
 libc/src/stdlib/strtold_l.h                   | 21 ++++++
 libc/src/stdlib/strtoll_l.cpp                 | 22 ++++++
 libc/src/stdlib/strtoll_l.h                   | 21 ++++++
 libc/src/stdlib/strtoull_l.cpp                | 22 ++++++
 libc/src/stdlib/strtoull_l.h                  | 22 ++++++
 libc/src/string/CMakeLists.txt                | 22 ++++++
 libc/src/string/strcoll_l.cpp                 | 22 ++++++
 libc/src/string/strcoll_l.h                   | 20 +++++
 libc/src/string/strxfrm_l.cpp                 | 23 ++++++
 libc/src/string/strxfrm_l.h                   | 23 ++++++
 61 files changed, 1323 insertions(+), 1 deletion(-)
 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/src/ctype/isdigit_l.cpp
 create mode 100644 libc/src/ctype/isdigit_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/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
 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/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/src/stdlib/strtod_l.cpp
 create mode 100644 libc/src/stdlib/strtod_l.h
 create mode 100644 libc/src/stdlib/strtof_l.cpp
 create mode 100644 libc/src/stdlib/strtof_l.h
 create mode 100644 libc/src/stdlib/strtold_l.cpp
 create mode 100644 libc/src/stdlib/strtold_l.h
 create mode 100644 libc/src/stdlib/strtoll_l.cpp
 create mode 100644 libc/src/stdlib/strtoll_l.h
 create mode 100644 libc/src/stdlib/strtoull_l.cpp
 create mode 100644 libc/src/stdlib/strtoull_l.h
 create mode 100644 libc/src/string/strcoll_l.cpp
 create mode 100644 libc/src/string/strcoll_l.h
 create mode 100644 libc/src/string/strxfrm_l.cpp
 create mode 100644 libc/src/string/strxfrm_l.h

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 940df63e3912b..8119cd6d300fe 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -17,6 +17,14 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.ctype.tolower
     libc.src.ctype.toupper
 
+    # ctype.h localized entrypoints
+    libc.src.ctype.isdigit_l
+    libc.src.ctype.isxdigit_l
+    libc.src.ctype.islower_l
+    libc.src.ctype.isupper_l
+    libc.src.ctype.tolower_l
+    libc.src.ctype.toupper_l
+
     # errno.h entrypoints
     libc.src.errno.errno
 
@@ -85,6 +93,10 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strtok
     libc.src.string.strtok_r
 
+    # string.h localized entrypoints
+    libc.src.string.strxfrm_l
+    libc.src.string.strcoll_l
+
     # inttypes.h entrypoints
     libc.src.inttypes.imaxabs
     libc.src.inttypes.imaxdiv
@@ -194,6 +206,13 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdlib.malloc
     libc.src.stdlib.realloc
 
+    # stdlib.h localized entrypoints
+    libc.src.stdlib.strtof_l
+    libc.src.stdlib.strtod_l
+    libc.src.stdlib.strtold_l
+    libc.src.stdlib.strtoull_l
+    libc.src.stdlib.strtoll_l
+
     # stdio.h entrypoints
     libc.src.stdio.fdopen
     #libc.src.stdio.fscanf
@@ -308,6 +327,14 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.unistd.unlink
     libc.src.unistd.unlinkat
     libc.src.unistd.write
+    
+    # locale.h entrypoints
+    libc.src.locale.duplocale
+    libc.src.locale.freelocale
+    libc.src.locale.localeconv
+    libc.src.locale.newlocale
+    libc.src.locale.setlocale
+    libc.src.locale.uselocale
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/aarch64/headers.txt b/libc/config/linux/aarch64/headers.txt
index 7d25877cefcc8..48716f8e2b404 100644
--- a/libc/config/linux/aarch64/headers.txt
+++ b/libc/config/linux/aarch64/headers.txt
@@ -31,4 +31,6 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.sys_ioctl
     # Disabled due to epoll_wait syscalls not being available on this platform.
     # libc.include.sys_epoll
+
+    libc.include.locale
 )
diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index eb0090c80b0da..ae94e2cf4b2c8 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -308,3 +308,10 @@ def SearchAPI : PublicAPI<"search.h"> {
 def SysStatvfsAPI : PublicAPI<"sys/statvfs.h"> {
   let Types = ["fsblkcnt_t", "fsfilcnt_t", "struct statvfs"];
 }
+
+def LocaleAPI : PublicAPI<"locale.h"> {
+  let Types = [
+    "struct lconv",
+    "locale_t"
+  ];
+}
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 09f04fb31dfd8..0b92b751d6c70 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -17,6 +17,14 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.ctype.tolower
     libc.src.ctype.toupper
 
+    # ctype.h localized entrypoints
+    libc.src.ctype.isdigit_l
+    libc.src.ctype.isxdigit_l
+    libc.src.ctype.islower_l
+    libc.src.ctype.isupper_l
+    libc.src.ctype.tolower_l
+    libc.src.ctype.toupper_l
+
     # errno.h entrypoints
     libc.src.errno.errno
 
@@ -87,6 +95,10 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.string.strtok_r
     libc.src.string.strxfrm
 
+    # string.h localized entrypoints
+    libc.src.string.strxfrm_l
+    libc.src.string.strcoll_l
+
     # inttypes.h entrypoints
     libc.src.inttypes.imaxabs
     libc.src.inttypes.imaxdiv
@@ -199,6 +211,13 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdlib.malloc
     libc.src.stdlib.realloc
 
+    # stdlib.h localized entrypoints
+    libc.src.stdlib.strtof_l
+    libc.src.stdlib.strtod_l
+    libc.src.stdlib.strtold_l
+    libc.src.stdlib.strtoull_l
+    libc.src.stdlib.strtoll_l
+
     # stdio.h entrypoints
     libc.src.stdio.fdopen
     libc.src.stdio.fileno
@@ -330,6 +349,14 @@ set(TARGET_LIBC_ENTRYPOINTS
 
     # wchar.h entrypoints
     libc.src.wchar.wctob
+
+    # locale.h entrypoints
+    libc.src.locale.duplocale
+    libc.src.locale.freelocale
+    libc.src.locale.localeconv
+    libc.src.locale.newlocale
+    libc.src.locale.setlocale
+    libc.src.locale.uselocale
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/x86_64/headers.txt b/libc/config/linux/x86_64/headers.txt
index 44d640b75e2bf..211354e20ad47 100644
--- a/libc/config/linux/x86_64/headers.txt
+++ b/libc/config/linux/x86_64/headers.txt
@@ -49,4 +49,6 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.sys_types
     libc.include.sys_utsname
     libc.include.sys_wait
+
+    libc.include.locale
 )
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 3ab7817d8568b..e47d0e81d5ec5 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -199,6 +199,8 @@ add_gen_header(
     .llvm-libc-types.struct_timespec
     .llvm-libc-types.struct_timeval
     .llvm-libc-types.clockid_t
+    .llvm-libc-types.size_t
+    .llvm-libc-types.locale_t
 )
 
 add_gen_header(
@@ -358,6 +360,17 @@ add_gen_header(
     .llvm-libc-types.posix_spawn_file_actions_t
 )
 
+add_gen_header(
+  locale
+  DEF_FILE locale.h.def
+  GEN_HDR locale.h
+  DEPENDS
+    .llvm_libc_common_h
+    .llvm-libc-types.struct_lconv
+    .llvm-libc-types.locale_t
+    .llvm-libc-macros.locale_macros
+)
+
 # TODO: Not all platforms will have a include/sys directory. Add the sys
 # directory and the targets for sys/*.h files conditional to the OS requiring
 # them.
diff --git a/libc/include/ctype.h.def b/libc/include/ctype.h.def
index a9bb786931ead..a6fc61a61fced 100644
--- a/libc/include/ctype.h.def
+++ b/libc/include/ctype.h.def
@@ -10,6 +10,7 @@
 #define LLVM_LIBC_CTYPE_H
 
 #include "__llvm-libc-common.h"
+#include "llvm-libc-types/locale_t.h"
 
 %%public_api()
 
diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt
index f6af11abd4dd7..05e1eb574f203 100644
--- a/libc/include/llvm-libc-macros/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/CMakeLists.txt
@@ -277,3 +277,9 @@ add_macro_header(
   HDR
     stdckdint-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 0000000000000..afc3fdbfdbd53
--- /dev/null
+++ b/libc/include/llvm-libc-macros/locale-macros.h
@@ -0,0 +1,30 @@
+//===-- 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
+
+// HACK(@izaakschroeder): Stubs
+#define LC_ALL 0
+#define LC_COLLATE 0
+#define LC_CTYPE 0
+#define LC_MESSAGES 0
+#define LC_MONETARY 0
+#define LC_NUMERIC 0
+#define LC_TIME 0
+
+// HACK(@izaakschroeder): Stubs
+#define LC_ALL_MASK 0
+#define LC_COLLATE_MASK 0
+#define LC_CTYPE_MASK 0
+#define LC_MESSAGES_MASK 0
+#define LC_MONETARY_MASK 0
+#define LC_NUMERIC_MASK 0
+#define LC_TIME_MASK 0
+
+#endif // LLVM_LIBC_MACROS_LOCALE_MACROS_H
diff --git a/libc/include/llvm-libc-macros/stdlib-macros.h b/libc/include/llvm-libc-macros/stdlib-macros.h
index 5fcbfef97b328..f53328b3d9e99 100644
--- a/libc/include/llvm-libc-macros/stdlib-macros.h
+++ b/libc/include/llvm-libc-macros/stdlib-macros.h
@@ -19,4 +19,8 @@
 
 #define RAND_MAX 2147483647
 
+// N.B. If current thread is utf8 then this is 4
+// otherwise it is 1. Leaving at 4 to be safe.
+#define MB_CUR_MAX 4
+
 #endif // LLVM_LIBC_MACROS_STDLIB_MACROS_H
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index d8b975572e0dd..5d579c832954d 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -89,6 +89,8 @@ add_header(thrd_t HDR thrd_t.h DEPENDS .__thread_type)
 add_header(tss_t HDR tss_t.h)
 add_header(tss_dtor_t HDR tss_dtor_t.h)
 add_header(__atexithandler_t HDR __atexithandler_t.h)
+add_header(struct_lconv HDR struct_lconv.h)
+add_header(locale_t HDR locale_t.h)
 add_header(speed_t HDR speed_t.h)
 add_header(tcflag_t HDR tcflag_t.h)
 add_header(struct_termios HDR struct_termios.h DEPENDS .cc_t .speed_t .tcflag_t)
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 0000000000000..35b0f9756eaef
--- /dev/null
+++ b/libc/include/llvm-libc-types/locale_t.h
@@ -0,0 +1,18 @@
+
+//===-- 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
+
+// HACK(@izaakschroeder): Placeholder.
+// NOTE: According to `libcxx` the `locale_t` type has to be at least
+// coercible to a `bool`.
+typedef void *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 0000000000000..27dd7048ec38b
--- /dev/null
+++ b/libc/include/llvm-libc-types/struct_lconv.h
@@ -0,0 +1,39 @@
+//===-- Definition of type struct 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_STRUCT_LCONV_H
+#define LLVM_LIBC_TYPES_STRUCT_LCONV_H
+
+struct lconv {
+  char *currency_symbol;
+  char *decimal_point;
+  char *grouping;
+  char *int_curr_symbol;
+  char *mon_decimal_point;
+  char *mon_grouping;
+  char *mon_thousands_sep;
+  char *negative_sign;
+  char *positive_sign;
+  char *thousands_sep;
+  char frac_digits;
+  char int_frac_digits;
+  char int_p_cs_precedes;
+  char int_p_sep_by_space;
+  char int_n_cs_precedes;
+  char int_n_sep_by_space;
+  char int_n_sign_posn;
+  char int_p_sign_posn;
+  char n_cs_precedes;
+  char n_sep_by_space;
+  char n_sign_posn;
+  char p_cs_precedes;
+  char p_sep_by_space;
+  char p_sign_posn;
+};
+
+#endif // LLVM_LIBC_TYPES_STRUCT_LCONV_H
diff --git a/libc/include/locale.h.def b/libc/include/locale.h.def
new file mode 100644
index 0000000000000..656344031d927
--- /dev/null
+++ b/libc/include/locale.h.def
@@ -0,0 +1,18 @@
+//===-- 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-macros/locale-macros.h"
+#include "llvm-libc-types/locale_t.h"
+#include "llvm-libc-types/struct_lconv.h"
+
+%%public_api()
+
+#endif // LLVM_LIBC_LINK_H
diff --git a/libc/include/stdlib.h.def b/libc/include/stdlib.h.def
index d523f7a53024a..34a11d4e78a77 100644
--- a/libc/include/stdlib.h.def
+++ b/libc/include/stdlib.h.def
@@ -11,6 +11,7 @@
 
 #include "__llvm-libc-common.h"
 #include "llvm-libc-macros/stdlib-macros.h"
+#include "llvm-libc-types/locale_t.h"
 
 %%public_api()
 
diff --git a/libc/include/time.h.def b/libc/include/time.h.def
index 2355e8822fad7..f23488720bac4 100644
--- a/libc/include/time.h.def
+++ b/libc/include/time.h.def
@@ -11,6 +11,8 @@
 
 #include "__llvm-libc-common.h"
 #include "llvm-libc-macros/time-macros.h"
+#include "llvm-libc-types/size_t.h"
+#include "llvm-libc-types/locale_t.h"
 
 %%public_api()
 
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index d14047548e104..565db1cc4ef35 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -21,6 +21,10 @@ def PThreadOnceT : NamedType<"pthread_once_t">;
 def PThreadOnceTPtr : PtrType<PThreadOnceT>;
 def PThreadOnceCallback : NamedType<"__pthread_once_func_t">;
 
+def StructLconv : NamedType<"struct lconv">;
+def StructLconvPtr : PtrType<StructLconv>;
+def LocaleT : NamedType<"locale_t">;
+
 def InoT : NamedType<"ino_t">;
 def UidT : NamedType<"uid_t">;
 def GidT : NamedType<"gid_t">;
@@ -1686,12 +1690,65 @@ def POSIX : StandardSpec<"POSIX"> {
     []  // Functions
   >;
 
+  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 = [
     ArpaInet,
     CType,
     Dirent,
     Errno,
     FCntl,
+    Locale,
     PThread,
     Sched,
     Signal,
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 9ff40bf76700c..ecea09f8af05c 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -2,12 +2,14 @@ def StdC : StandardSpec<"stdc"> {
 
   NamedType StructTmType = NamedType<"struct tm">;
   PtrType StructTmPtr = PtrType<StructTmType>;
+
   PtrType TimeTTypePtr = PtrType<TimeTType>;
   NamedType ClockT = NamedType<"clock_t">;
 
   NamedType DivTType = NamedType<"div_t">;
   NamedType LDivTType = NamedType<"ldiv_t">;
   NamedType LLDivTType = NamedType<"lldiv_t">;
+  NamedType LocaleTType = NamedType<"locale_t">;
 
   NamedType JmpBuf = NamedType<"jmp_buf">;
 
@@ -107,6 +109,36 @@ def StdC : StandardSpec<"stdc"> {
               RetValSpec<IntType>,
               [ArgSpec<IntType>]
           >,
+          FunctionSpec<
+              "isdigit_l",
+              RetValSpec<IntType>,
+              [ArgSpec<IntType>, ArgSpec<LocaleTType>]
+          >,
+          FunctionSpec<
+              "isxdigit_l",
+              RetValSpec<IntType>,
+              [ArgSpec<IntType>, ArgSpec<LocaleTType>]
+          >,
+          FunctionSpec<
+              "tolower_l",
+              RetValSpec<IntType>,
+              [ArgSpec<IntType>, ArgSpec<LocaleTType>]
+          >,
+          FunctionSpec<
+              "toupper_l",
+              RetValSpec<IntType>,
+              [ArgSpec<IntType>, ArgSpec<LocaleTType>]
+          >,
+          FunctionSpec<
+              "islower_l",
+              RetValSpec<IntType>,
+              [ArgSpec<IntType>, ArgSpec<LocaleTType>]
+          >,
+          FunctionSpec<
+              "isupper_l",
+              RetValSpec<IntType>,
+              [ArgSpec<IntType>, ArgSpec<LocaleTType>]
+          >,
       ]
   >;
 
@@ -1139,6 +1171,29 @@ def StdC : StandardSpec<"stdc"> {
           FunctionSpec<"strtoul", RetValSpec<UnsignedLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>]>,
           FunctionSpec<"strtoull", RetValSpec<UnsignedLongLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>]>,
 
+
+          FunctionSpec<"strtof_l", RetValSpec<FloatType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<LocaleTType>]>,
+          FunctionSpec<"strtod_l", RetValSpec<DoubleType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<LocaleTType>]>,
+          FunctionSpec<"strtold_l", RetValSpec<LongDoubleType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<LocaleTType>]>,
+          FunctionSpec<"strtol_l", RetValSpec<LongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>, ArgSpec<LocaleTType>]>,
+          FunctionSpec<"strtoll_l", RetValSpec<LongLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>, ArgSpec<LocaleTType>]>,
+          FunctionSpec<"strtoul_l", RetValSpec<UnsignedLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>, ArgSpec<LocaleTType>]>,
+          FunctionSpec<"strtoull_l", RetValSpec<UnsignedLongLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>, ArgSpec<LocaleTType>]>,
+
+          FunctionSpec<
+              "strxfrm_l",
+              RetValSpec<SizeTType>,
+              [ArgSpec<CharRestrictedPtr>,
+               ArgSpec<ConstCharRestrictedPtr>,
+               ArgSpec<SizeTType>,
+               ArgSpec<LocaleTType>]
+          >,
+          FunctionSpec<
+              "strcoll_l",
+              RetValSpec<IntType>,
+              [ArgSpec<ConstCharPtr>, ArgSpec<ConstCharPtr>, ArgSpec<LocaleTType>]
+          >,
+
           FunctionSpec<"malloc", RetValSpec<VoidPtr>, [ArgSpec<SizeTType>]>,
           FunctionSpec<"calloc", RetValSpec<VoidPtr>, [ArgSpec<SizeTType>, ArgSpec<SizeTType>]>,
           FunctionSpec<"realloc", RetValSpec<VoidPtr>, [ArgSpec<VoidPtr>, ArgSpec<SizeTType>]>,
@@ -1439,7 +1494,7 @@ def StdC : StandardSpec<"stdc"> {
               "mktime",
               RetValSpec<TimeTType>,
               [ArgSpec<StructTmPtr>]
-          >,
+          >,      
           FunctionSpec<
               "time",
               RetValSpec<TimeTType>,
diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index 09b16be1e2d42..00dc2bba141aa 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -4,6 +4,7 @@ add_subdirectory(ctype)
 add_subdirectory(errno)
 add_subdirectory(fenv)
 add_subdirectory(inttypes)
+add_subdirectory(locale)
 add_subdirectory(math)
 add_subdirectory(stdbit)
 add_subdirectory(stdfix)
diff --git a/libc/src/ctype/CMakeLists.txt b/libc/src/ctype/CMakeLists.txt
index ae4eec9615dc1..19e5ef609e93c 100644
--- a/libc/src/ctype/CMakeLists.txt
+++ b/libc/src/ctype/CMakeLists.txt
@@ -146,3 +146,76 @@ add_entrypoint_object(
   DEPENDS
     libc.src.__support.ctype_utils
 )
+
+add_entrypoint_object(
+  isdigit_l
+  SRCS
+    isdigit_l.cpp
+  HDRS
+    isdigit_l.h
+  DEPENDS
+    libc.src.ctype.isdigit
+    libc.include.llvm-libc-types.locale_t
+    libc.src.__support.ctype_utils
+)
+
+add_entrypoint_object(
+  isxdigit_l
+  SRCS
+    isxdigit_l.cpp
+  HDRS
+    isxdigit_l.h
+  DEPENDS
+    libc.src.ctype.isxdigit
+    libc.include.llvm-libc-types.locale_t
+    libc.src.__support.ctype_utils
+)
+
+
+add_entrypoint_object(
+  islower_l
+  SRCS
+    islower_l.cpp
+  HDRS
+    islower_l.h
+  DEPENDS
+    libc.src.ctype.islower
+    libc.include.llvm-libc-types.locale_t
+    libc.src.__support.ctype_utils
+)
+
+add_entrypoint_object(
+  isupper_l
+  SRCS
+    isupper_l.cpp
+  HDRS
+    isupper_l.h
+  DEPENDS
+    libc.src.ctype.isupper
+    libc.include.llvm-libc-types.locale_t
+    libc.src.__support.ctype_utils
+)
+
+add_entrypoint_object(
+  tolower_l
+  SRCS
+    tolower_l.cpp
+  HDRS
+    tolower_l.h
+  DEPENDS
+    libc.src.ctype.tolower
+    libc.include.llvm-libc-types.locale_t
+    libc.src.__support.ctype_utils
+)
+
+add_entrypoint_object(
+  toupper_l
+  SRCS
+    toupper_l.cpp
+  HDRS
+    toupper_l.h
+  DEPENDS
+    libc.src.ctype.toupper
+    libc.include.llvm-libc-types.locale_t
+    libc.src.__support.ctype_utils
+)
diff --git a/libc/src/ctype/isdigit_l.cpp b/libc/src/ctype/isdigit_l.cpp
new file mode 100644
index 0000000000000..5ae615177ebc3
--- /dev/null
+++ b/libc/src/ctype/isdigit_l.cpp
@@ -0,0 +1,17 @@
+//===-- 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/ctype/isdigit.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, isdigit_l, (int c, locale_t)) { return isdigit(c); }
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/ctype/isdigit_l.h b/libc/src/ctype/isdigit_l.h
new file mode 100644
index 0000000000000..eca38c198b816
--- /dev/null
+++ b/libc/src/ctype/isdigit_l.h
@@ -0,0 +1,20 @@
+//===-- 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_L_H
+#define LLVM_LIBC_SRC_CTYPE_ISDIGIT_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+int isdigit_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif //  LLVM_LIBC_SRC_CTYPE_ISDIGIT_L_H
diff --git a/libc/src/ctype/islower_l.cpp b/libc/src/ctype/islower_l.cpp
new file mode 100644
index 0000000000000..2e4cfcb7560a7
--- /dev/null
+++ b/libc/src/ctype/islower_l.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of islower_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/islower_l.h"
+#include "src/ctype/islower.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+// TODO: Currently restricted to default locale.
+// These should be extended using locale information.
+LLVM_LIBC_FUNCTION(int, islower_l, (int c, locale_t)) { return islower(c); }
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/ctype/islower_l.h b/libc/src/ctype/islower_l.h
new file mode 100644
index 0000000000000..dee277ce9af97
--- /dev/null
+++ b/libc/src/ctype/islower_l.h
@@ -0,0 +1,20 @@
+//===-- 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_L_H
+#define LLVM_LIBC_SRC_CTYPE_ISLOWER_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+int islower_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif //  LLVM_LIBC_SRC_CTYPE_ISLOWER_L_H
diff --git a/libc/src/ctype/isupper_l.cpp b/libc/src/ctype/isupper_l.cpp
new file mode 100644
index 0000000000000..38a8a90717082
--- /dev/null
+++ b/libc/src/ctype/isupper_l.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of isupper_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/isupper_l.h"
+#include "src/ctype/isupper.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+// TODO: Currently restricted to default locale.
+// These should be extended using locale information.
+LLVM_LIBC_FUNCTION(int, isupper_l, (int c, locale_t)) { return isupper(c); }
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/ctype/isupper_l.h b/libc/src/ctype/isupper_l.h
new file mode 100644
index 0000000000000..fbd49c97cb7fa
--- /dev/null
+++ b/libc/src/ctype/isupper_l.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for isupper -------------------------*-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_L_H
+#define LLVM_LIBC_SRC_CTYPE_ISUPPER_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+int isupper_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif //  LLVM_LIBC_SRC_CTYPE_ISUPPER_L_H
diff --git a/libc/src/ctype/isxdigit_l.cpp b/libc/src/ctype/isxdigit_l.cpp
new file mode 100644
index 0000000000000..8e1333331ec74
--- /dev/null
+++ b/libc/src/ctype/isxdigit_l.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of isxdigit_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/isxdigit_l.h"
+#include "src/__support/ctype_utils.h"
+#include "src/ctype/isxdigit.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+// TODO: Currently restricted to default locale.
+// These should be extended using locale information.
+LLVM_LIBC_FUNCTION(int, isxdigit_l, (int c, locale_t)) { return isxdigit(c); }
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/ctype/isxdigit_l.h b/libc/src/ctype/isxdigit_l.h
new file mode 100644
index 0000000000000..875f584ba0a10
--- /dev/null
+++ b/libc/src/ctype/isxdigit_l.h
@@ -0,0 +1,20 @@
+//===-- 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_L_H
+#define LLVM_LIBC_SRC_CTYPE_ISXDIGIT_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+int isxdigit_l(int c, locale_t);
+
+} // namespace LIBC_NAMESPACE
+
+#endif //  LLVM_LIBC_SRC_CTYPE_ISXDIGIT_L_H
diff --git a/libc/src/ctype/tolower_l.cpp b/libc/src/ctype/tolower_l.cpp
new file mode 100644
index 0000000000000..c89c6d7038138
--- /dev/null
+++ b/libc/src/ctype/tolower_l.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of tolower_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/tolower_l.h"
+#include "src/ctype/tolower.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+// TODO: Currently restricted to default locale.
+// These should be extended using locale information.
+LLVM_LIBC_FUNCTION(int, tolower_l, (int c, locale_t)) { return tolower(c); }
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/ctype/tolower_l.h b/libc/src/ctype/tolower_l.h
new file mode 100644
index 0000000000000..624526dbe8f30
--- /dev/null
+++ b/libc/src/ctype/tolower_l.h
@@ -0,0 +1,20 @@
+//===-- 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_L_H
+#define LLVM_LIBC_SRC_CTYPE_TOLOWER_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+int tolower_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif //  LLVM_LIBC_SRC_CTYPE_TOLOWER_L_H
diff --git a/libc/src/ctype/toupper_l.cpp b/libc/src/ctype/toupper_l.cpp
new file mode 100644
index 0000000000000..59ab613ffa861
--- /dev/null
+++ b/libc/src/ctype/toupper_l.cpp
@@ -0,0 +1,21 @@
+//===-- 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/ctype/toupper.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+// TODO: Currently restricted to default locale.
+// These should be extended using locale information.
+LLVM_LIBC_FUNCTION(int, toupper_l, (int c, locale_t)) { return toupper(c); }
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/ctype/toupper_l.h b/libc/src/ctype/toupper_l.h
new file mode 100644
index 0000000000000..22a6b5c968b63
--- /dev/null
+++ b/libc/src/ctype/toupper_l.h
@@ -0,0 +1,20 @@
+//===-- 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_L_H
+#define LLVM_LIBC_SRC_CTYPE_TOUPPER_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+int toupper_l(int c, locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif //  LLVM_LIBC_SRC_CTYPE_TOUPPER_L_H
diff --git a/libc/src/locale/CMakeLists.txt b/libc/src/locale/CMakeLists.txt
new file mode 100644
index 0000000000000..be955c39f496f
--- /dev/null
+++ b/libc/src/locale/CMakeLists.txt
@@ -0,0 +1,60 @@
+add_entrypoint_object(
+  duplocale
+  SRCS
+    duplocale.cpp
+  HDRS
+    duplocale.h
+  DEPENDS
+    libc.src.__support.common
+)
+
+add_entrypoint_object(
+  freelocale
+  SRCS
+    freelocale.cpp
+  HDRS
+    freelocale.h
+  DEPENDS
+    libc.src.__support.common
+)
+
+add_entrypoint_object(
+  localeconv
+  SRCS
+    localeconv.cpp
+  HDRS
+    localeconv.h
+  DEPENDS
+    libc.src.__support.common
+    libc.include.limits
+)
+
+add_entrypoint_object(
+  newlocale
+  SRCS
+    newlocale.cpp
+  HDRS
+    newlocale.h
+  DEPENDS
+    libc.src.__support.common
+)
+
+add_entrypoint_object(
+  setlocale
+  SRCS
+    setlocale.cpp
+  HDRS
+    setlocale.h
+  DEPENDS
+    libc.src.__support.common
+)
+
+add_entrypoint_object(
+  uselocale
+  SRCS
+    uselocale.cpp
+  HDRS
+    uselocale.h
+  DEPENDS
+    libc.src.__support.common
+)
diff --git a/libc/src/locale/duplocale.cpp b/libc/src/locale/duplocale.cpp
new file mode 100644
index 0000000000000..3c0a0f668856c
--- /dev/null
+++ b/libc/src/locale/duplocale.cpp
@@ -0,0 +1,16 @@
+//===-- 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 "duplocale.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(locale_t, duplocale, (locale_t locale)) { return locale; }
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/locale/duplocale.h b/libc/src/locale/duplocale.h
new file mode 100644
index 0000000000000..87a613beada09
--- /dev/null
+++ b/libc/src/locale/duplocale.h
@@ -0,0 +1,20 @@
+//===-- 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 "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+locale_t duplocale(locale_t);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_LINK_DL_ITERATE_PHDR_H
diff --git a/libc/src/locale/freelocale.cpp b/libc/src/locale/freelocale.cpp
new file mode 100644
index 0000000000000..317b6cb0002df
--- /dev/null
+++ b/libc/src/locale/freelocale.cpp
@@ -0,0 +1,18 @@
+//===-- 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 "freelocale.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(void, freelocale, (locale_t)) {
+  // ...
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/locale/freelocale.h b/libc/src/locale/freelocale.h
new file mode 100644
index 0000000000000..eec66b618ebe7
--- /dev/null
+++ b/libc/src/locale/freelocale.h
@@ -0,0 +1,20 @@
+//===-- 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 "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+void freelocale(locale_t);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_LOCALE_FREELOCALE_H
diff --git a/libc/src/locale/localeconv.cpp b/libc/src/locale/localeconv.cpp
new file mode 100644
index 0000000000000..fd9a081198498
--- /dev/null
+++ b/libc/src/locale/localeconv.cpp
@@ -0,0 +1,46 @@
+//===-- 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 "localeconv.h"
+#include "src/__support/common.h"
+#include <limits.h>
+
+namespace LIBC_NAMESPACE {
+
+static const struct lconv posix_lconv = {
+    .currency_symbol = const_cast<char *>(""),
+    .decimal_point = const_cast<char *>("."),
+    .grouping = const_cast<char *>(""),
+    .int_curr_symbol = const_cast<char *>(""),
+    .mon_decimal_point = const_cast<char *>(""),
+    .mon_grouping = const_cast<char *>(""),
+    .mon_thousands_sep = const_cast<char *>(""),
+    .negative_sign = const_cast<char *>(""),
+    .positive_sign = const_cast<char *>(""),
+    .thousands_sep = const_cast<char *>(""),
+    .frac_digits = CHAR_MAX,
+    .int_frac_digits = CHAR_MAX,
+    .int_p_cs_precedes = CHAR_MAX,
+    .int_p_sep_by_space = CHAR_MAX,
+    .int_n_cs_precedes = CHAR_MAX,
+    .int_n_sep_by_space = CHAR_MAX,
+    .int_n_sign_posn = CHAR_MAX,
+    .int_p_sign_posn = CHAR_MAX,
+    .n_cs_precedes = CHAR_MAX,
+    .n_sep_by_space = CHAR_MAX,
+    .n_sign_posn = CHAR_MAX,
+    .p_cs_precedes = CHAR_MAX,
+    .p_sep_by_space = CHAR_MAX,
+    .p_sign_posn = CHAR_MAX,
+};
+
+LLVM_LIBC_FUNCTION(struct lconv *, localeconv, ()) {
+  return const_cast<struct lconv *>(&posix_lconv);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/locale/localeconv.h b/libc/src/locale/localeconv.h
new file mode 100644
index 0000000000000..e095be7334365
--- /dev/null
+++ b/libc/src/locale/localeconv.h
@@ -0,0 +1,20 @@
+//===-- 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 "include/llvm-libc-types/struct_lconv.h"
+
+namespace LIBC_NAMESPACE {
+
+struct lconv *localeconv(void);
+
+} // namespace LIBC_NAMESPACE
+
+#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 0000000000000..332f40bd7ba8f
--- /dev/null
+++ b/libc/src/locale/newlocale.cpp
@@ -0,0 +1,18 @@
+//===-- 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 "newlocale.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(locale_t, newlocale, (int, const char *, locale_t locale)) {
+  return locale;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/locale/newlocale.h b/libc/src/locale/newlocale.h
new file mode 100644
index 0000000000000..d8a0f66e7f060
--- /dev/null
+++ b/libc/src/locale/newlocale.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for newlocale ---------------------*- 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_NEWLOCALE_H
+#define LLVM_LIBC_SRC_LOCALE_NEWLOCALE_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+locale_t newlocale(int, const char *, locale_t);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_LOCALE_NEWLOCALE_H
diff --git a/libc/src/locale/setlocale.cpp b/libc/src/locale/setlocale.cpp
new file mode 100644
index 0000000000000..9a5aba412776c
--- /dev/null
+++ b/libc/src/locale/setlocale.cpp
@@ -0,0 +1,18 @@
+//===-- 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 "setlocale.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(char *, setlocale, (int, const char *)) {
+  return const_cast<char *>("unsupported");
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/locale/setlocale.h b/libc/src/locale/setlocale.h
new file mode 100644
index 0000000000000..a438c8426a2b7
--- /dev/null
+++ b/libc/src/locale/setlocale.h
@@ -0,0 +1,18 @@
+//===-- 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
+
+namespace LIBC_NAMESPACE {
+
+char *setlocale(int, const char *);
+
+} // namespace LIBC_NAMESPACE
+
+#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 0000000000000..b614313ac7f78
--- /dev/null
+++ b/libc/src/locale/uselocale.cpp
@@ -0,0 +1,16 @@
+//===-- 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 "uselocale.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(locale_t, uselocale, (locale_t locale)) { return locale; }
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/locale/uselocale.h b/libc/src/locale/uselocale.h
new file mode 100644
index 0000000000000..48abb54cbfcfe
--- /dev/null
+++ b/libc/src/locale/uselocale.h
@@ -0,0 +1,20 @@
+//===-- 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 "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+locale_t uselocale(locale_t);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_LOCALE_USELOCALE_H
diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index 677bf358c82c4..4fc93c7bcdb91 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -516,3 +516,63 @@ add_entrypoint_object(
   DEPENDS
     .${LIBC_TARGET_OS}.abort
 )
+
+add_entrypoint_object(
+  strtof_l
+  SRCS
+    strtof_l.cpp
+  HDRS
+    strtof_l.h
+  DEPENDS
+    libc.src.stdlib.strtof
+    libc.src.errno.errno
+    libc.include.llvm-libc-types.locale_t
+)
+
+add_entrypoint_object(
+  strtod_l
+  SRCS
+    strtod_l.cpp
+  HDRS
+    strtod_l.h
+  DEPENDS
+    libc.src.stdlib.strtod
+    libc.src.errno.errno
+    libc.include.llvm-libc-types.locale_t
+)
+
+add_entrypoint_object(
+  strtold_l
+  SRCS
+    strtold_l.cpp
+  HDRS
+    strtold_l.h
+  DEPENDS
+    libc.src.stdlib.strtold
+    libc.src.errno.errno
+    libc.include.llvm-libc-types.locale_t
+)
+
+add_entrypoint_object(
+  strtoull_l
+  SRCS
+    strtoull_l.cpp
+  HDRS
+    strtoull_l.h
+  DEPENDS
+    libc.src.stdlib.strtoull
+    libc.src.errno.errno
+    libc.include.llvm-libc-types.locale_t
+)
+
+add_entrypoint_object(
+  strtoll_l
+  SRCS
+    strtoll_l.cpp
+  HDRS
+    strtoll_l.h
+  DEPENDS
+    libc.src.stdlib.strtoll
+    libc.src.errno.errno
+    libc.include.llvm-libc-types.locale_t
+)
diff --git a/libc/src/stdlib/strtod_l.cpp b/libc/src/stdlib/strtod_l.cpp
new file mode 100644
index 0000000000000..898a925d5face
--- /dev/null
+++ b/libc/src/stdlib/strtod_l.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of strtod_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/stdlib/strtod_l.h"
+#include "src/__support/common.h"
+#include "src/stdlib/strtod.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(double, strtod_l,
+                   (const char *__restrict str, char **__restrict str_end,
+                    locale_t)) {
+  return strtod(str, str_end);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdlib/strtod_l.h b/libc/src/stdlib/strtod_l.h
new file mode 100644
index 0000000000000..6e130f332e127
--- /dev/null
+++ b/libc/src/stdlib/strtod_l.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for strtod_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_STDLIB_STRTOD_L_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOD_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+double strtod_l(const char *__restrict str, char **__restrict str_end,
+                locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOD_L_H
diff --git a/libc/src/stdlib/strtof_l.cpp b/libc/src/stdlib/strtof_l.cpp
new file mode 100644
index 0000000000000..c5d25e60be02b
--- /dev/null
+++ b/libc/src/stdlib/strtof_l.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of strtof_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/stdlib/strtof_l.h"
+#include "src/__support/common.h"
+#include "src/stdlib/strtof.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(float, strtof_l,
+                   (const char *__restrict str, char **__restrict str_end,
+                    locale_t)) {
+  return strtof(str, str_end);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdlib/strtof_l.h b/libc/src/stdlib/strtof_l.h
new file mode 100644
index 0000000000000..40552ba2d87ef
--- /dev/null
+++ b/libc/src/stdlib/strtof_l.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for strtof_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_STDLIB_STRTOF_L_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOF_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+float strtof_l(const char *__restrict str, char **__restrict str_end,
+               locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOF_L_H
diff --git a/libc/src/stdlib/strtold_l.cpp b/libc/src/stdlib/strtold_l.cpp
new file mode 100644
index 0000000000000..245356ce08ea6
--- /dev/null
+++ b/libc/src/stdlib/strtold_l.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of strtold_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/stdlib/strtold_l.h"
+#include "src/__support/common.h"
+#include "src/stdlib/strtold.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(long double, strtold_l,
+                   (const char *__restrict str, char **__restrict str_end,
+                    locale_t)) {
+
+  return strtold(str, str_end);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdlib/strtold_l.h b/libc/src/stdlib/strtold_l.h
new file mode 100644
index 0000000000000..d156f46d50ac9
--- /dev/null
+++ b/libc/src/stdlib/strtold_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for strtold_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_STDLIB_STRTOLD_L_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOLD_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+long double strtold_l(const char *__restrict str, char **__restrict str_end,
+                      locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOLD_L_H
diff --git a/libc/src/stdlib/strtoll_l.cpp b/libc/src/stdlib/strtoll_l.cpp
new file mode 100644
index 0000000000000..e3a6c89a2a23d
--- /dev/null
+++ b/libc/src/stdlib/strtoll_l.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of strtoll_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/stdlib/strtoll_l.h"
+#include "src/__support/common.h"
+#include "src/stdlib/strtoll.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(long long, strtoll_l,
+                   (const char *__restrict str, char **__restrict str_end,
+                    int base, locale_t)) {
+
+  return strtoll(str, str_end, base);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdlib/strtoll_l.h b/libc/src/stdlib/strtoll_l.h
new file mode 100644
index 0000000000000..96cab62897039
--- /dev/null
+++ b/libc/src/stdlib/strtoll_l.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for strtoll -----------------------*- 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_STDLIB_STRTOLL_L_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOLL_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+long long strtoll_l(const char *__restrict str, char **__restrict str_end,
+                    int base, locale_t);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOLL_L_H
diff --git a/libc/src/stdlib/strtoull_l.cpp b/libc/src/stdlib/strtoull_l.cpp
new file mode 100644
index 0000000000000..72f8fd011d51f
--- /dev/null
+++ b/libc/src/stdlib/strtoull_l.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of strtoull_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/stdlib/strtoull_l.h"
+#include "src/__support/common.h"
+#include "src/stdlib/strtoull.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(unsigned long long, strtoull_l,
+                   (const char *__restrict str, char **__restrict str_end,
+                    int base, locale_t)) {
+
+  return strtoull(str, str_end, base);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdlib/strtoull_l.h b/libc/src/stdlib/strtoull_l.h
new file mode 100644
index 0000000000000..6c24ecd3abbb1
--- /dev/null
+++ b/libc/src/stdlib/strtoull_l.h
@@ -0,0 +1,22 @@
+//===-- Implementation header for strtoull_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_STDLIB_STRTOULL_L_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOULL_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+unsigned long long strtoull_l(const char *__restrict str,
+                              char **__restrict str_end, int base,
+                              locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOULL_L_H
diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt
index 56588ffafb86f..794e9206aded4 100644
--- a/libc/src/string/CMakeLists.txt
+++ b/libc/src/string/CMakeLists.txt
@@ -452,6 +452,28 @@ add_entrypoint_object(
     .memory_utils.inline_memset
 )
 
+add_entrypoint_object(
+  strcoll_l
+  SRCS
+    strcoll_l.cpp
+  HDRS
+    strcoll_l.h
+  DEPENDS
+    .strcoll
+    libc.include.llvm-libc-types.locale_t
+)
+
+add_entrypoint_object(
+  strxfrm_l
+  SRCS
+    strxfrm_l.cpp
+  HDRS
+    strxfrm_l.h
+  DEPENDS
+    .strxfrm
+    libc.include.llvm-libc-types.locale_t
+)
+
 # Helper to define a function with multiple implementations
 # - Computes flags to satisfy required/rejected features and arch,
 # - Declares an entry point,
diff --git a/libc/src/string/strcoll_l.cpp b/libc/src/string/strcoll_l.cpp
new file mode 100644
index 0000000000000..8bfef08d91619
--- /dev/null
+++ b/libc/src/string/strcoll_l.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of strcoll_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/string/strcoll_l.h"
+#include "src/string/strcoll.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+// TODO: Add support for locales.
+LLVM_LIBC_FUNCTION(int, strcoll_l,
+                   (const char *left, const char *right, locale_t)) {
+  return strcoll(left, right);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/string/strcoll_l.h b/libc/src/string/strcoll_l.h
new file mode 100644
index 0000000000000..0eee80125a942
--- /dev/null
+++ b/libc/src/string/strcoll_l.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for strcoll_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_STRING_STRCOLL_L_H
+#define LLVM_LIBC_SRC_STRING_STRCOLL_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+
+namespace LIBC_NAMESPACE {
+
+int strcoll_l(const char *left, const char *right, locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STRING_STRCOLL_L_H
diff --git a/libc/src/string/strxfrm_l.cpp b/libc/src/string/strxfrm_l.cpp
new file mode 100644
index 0000000000000..8e929185a61c6
--- /dev/null
+++ b/libc/src/string/strxfrm_l.cpp
@@ -0,0 +1,23 @@
+//===-- Implementation of strxfrm_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/string/strxfrm_l.h"
+#include "src/string/strxfrm.h"
+
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+// TODO: Add support for locales.
+LLVM_LIBC_FUNCTION(size_t, strxfrm_l,
+                   (char *__restrict dest, const char *__restrict src, size_t n,
+                    locale_t)) {
+  return strxfrm(dest, src, n);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/string/strxfrm_l.h b/libc/src/string/strxfrm_l.h
new file mode 100644
index 0000000000000..d56a6ff073e9b
--- /dev/null
+++ b/libc/src/string/strxfrm_l.h
@@ -0,0 +1,23 @@
+//===-- Implementation header for strxfrm_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_STRING_STRXFRM_L_H
+#define LLVM_LIBC_SRC_STRING_STRXFRM_L_H
+
+#include "include/llvm-libc-types/locale_t.h"
+#include <stddef.h> // For size_t
+
+namespace LIBC_NAMESPACE {
+
+size_t strxfrm_l(char *__restrict dest, const char *__restrict src, size_t n,
+                 locale_t locale);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STRING_STRXFRM_L_H



More information about the libc-commits mailing list