[libc-commits] [libc] [libc] Initial support for 'locale.h' in the LLVM libc (PR #102689)

Joseph Huber via libc-commits libc-commits at lists.llvm.org
Wed Aug 21 11:01:12 PDT 2024


https://github.com/jhuber6 updated https://github.com/llvm/llvm-project/pull/102689

>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 cbd92dd5624cabd18fe6f02b5d9c5aa686880e7a Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Wed, 21 Aug 2024 13:01:03 -0500
Subject: [PATCH 2/2] Update locale.cpp

---
 libc/src/locale/locale.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/locale/locale.cpp b/libc/src/locale/locale.cpp
index 18ebc33ad58234..1610fb5dd34004 100644
--- a/libc/src/locale/locale.cpp
+++ b/libc/src/locale/locale.cpp
@@ -16,6 +16,6 @@ namespace LIBC_NAMESPACE_DECL {
 
 __locale_t c_locale = {nullptr};
 
-LIBC_THREAD_LOCAL locale_t locale = nullptr;
+locale_t locale = nullptr;
 
 } // namespace LIBC_NAMESPACE_DECL



More information about the libc-commits mailing list