diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 8314df89b0636..565fbf78fcb96 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -2,8 +2,12 @@ set(TARGET_LIBC_ENTRYPOINTS # ctype.h entrypoints libc.src.ctype.isalnum libc.src.ctype.isalpha + libc.src.ctype.isblank + libc.src.ctype.iscntrl libc.src.ctype.isdigit + libc.src.ctype.isgraph libc.src.ctype.islower + libc.src.ctype.ispunct libc.src.ctype.isupper # errno.h entrypoints diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td index 03d5d66e41e79..a57c703a699e7 100644 --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -90,8 +90,12 @@ def CTypeAPI : PublicAPI<"ctype.h"> { let Functions = [ "isalnum", "isalpha", + "isblank", + "iscntrl", "isdigit", + "isgraph", "islower", + "ispunct", "isupper", ]; } diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 56a99d00d7847..3cc243e426c27 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -5,8 +5,12 @@ set(TARGET_LIBC_ENTRYPOINTS # ctype.h entrypoints libc.src.ctype.isalnum libc.src.ctype.isalpha + libc.src.ctype.isblank + libc.src.ctype.iscntrl libc.src.ctype.isdigit + libc.src.ctype.isgraph libc.src.ctype.islower + libc.src.ctype.ispunct libc.src.ctype.isupper # errno.h entrypoints diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td index 4fffc5cdc8579..1f14f76553593 100644 --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -56,16 +56,36 @@ def StdC : StandardSpec<"stdc"> { RetValSpec, [ArgSpec] >, + FunctionSpec< + "isblank", + RetValSpec, + [ArgSpec] + >, + FunctionSpec< + "iscntrl", + RetValSpec, + [ArgSpec] + >, FunctionSpec< "isdigit", RetValSpec, [ArgSpec] >, + FunctionSpec< + "isgraph", + RetValSpec, + [ArgSpec] + >, FunctionSpec< "islower", RetValSpec, [ArgSpec] >, + FunctionSpec< + "ispunct", + RetValSpec, + [ArgSpec] + >, FunctionSpec< "isupper", RetValSpec, diff --git a/libc/src/ctype/CMakeLists.txt b/libc/src/ctype/CMakeLists.txt index 30995ab2f714c..c554e6cb78510 100644 --- a/libc/src/ctype/CMakeLists.txt +++ b/libc/src/ctype/CMakeLists.txt @@ -24,6 +24,22 @@ add_entrypoint_object( .ctype_utils ) +add_entrypoint_object( + isblank + SRCS + isblank.cpp + HDRS + isblank.h +) + +add_entrypoint_object( + iscntrl + SRCS + iscntrl.cpp + HDRS + iscntrl.h +) + add_entrypoint_object( isdigit SRCS @@ -34,6 +50,16 @@ add_entrypoint_object( .ctype_utils ) +add_entrypoint_object( + isgraph + SRCS + isgraph.cpp + HDRS + isgraph.h + DEPENDS + .ctype_utils +) + add_entrypoint_object( islower SRCS @@ -42,6 +68,16 @@ add_entrypoint_object( islower.h ) +add_entrypoint_object( + ispunct + SRCS + ispunct.cpp + HDRS + ispunct.h + DEPENDS + .ctype_utils +) + add_entrypoint_object( isupper SRCS diff --git a/libc/src/ctype/ctype_utils.h b/libc/src/ctype/ctype_utils.h index 4e8d3960bb704..787a19ebf1328 100644 --- a/libc/src/ctype/ctype_utils.h +++ b/libc/src/ctype/ctype_utils.h @@ -18,15 +18,13 @@ namespace internal { // of a function call by inlining them. // ------------------------------------------------------ -static inline int isdigit(int c) { - const unsigned ch = c; - return (ch - '0') < 10; -} - -static inline int isalpha(int c) { - const unsigned ch = c; - return (ch | 32) - 'a' < 26; -} +static inline int isdigit(unsigned ch) { return (ch - '0') < 10; } + +static inline int isalpha(unsigned ch) { return (ch | 32) - 'a' < 26; } + +static inline int isalnum(unsigned ch) { return isalpha(ch) || isdigit(ch); } + +static inline int isgraph(unsigned ch) { return 0x20 < ch && ch < 0x7f; } } // namespace internal } // namespace __llvm_libc diff --git a/libc/src/ctype/isalnum.cpp b/libc/src/ctype/isalnum.cpp index 08b6520e44267..54c4f80984195 100644 --- a/libc/src/ctype/isalnum.cpp +++ b/libc/src/ctype/isalnum.cpp @@ -15,8 +15,6 @@ namespace __llvm_libc { // TODO: Currently restricted to default locale. // These should be extended using locale information. -int LLVM_LIBC_ENTRYPOINT(isalnum)(int c) { - return internal::isalpha(c) || internal::isdigit(c); -} +int LLVM_LIBC_ENTRYPOINT(isalnum)(int c) { return internal::isalnum(c); } } // namespace __llvm_libc diff --git a/libc/src/ctype/isblank.cpp b/libc/src/ctype/isblank.cpp new file mode 100644 index 0000000000000..fa28d84c03bd0 --- /dev/null +++ b/libc/src/ctype/isblank.cpp @@ -0,0 +1,22 @@ +//===-- Implementation of isblank------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/ctype/isblank.h" + +#include "src/__support/common.h" + +namespace __llvm_libc { + +// TODO: Currently restricted to default locale. +// These should be extended using locale information. +int LLVM_LIBC_ENTRYPOINT(isblank)(int c) { + const unsigned char ch = c; + return ch == ' ' || ch == '\t'; +} + +} // namespace __llvm_libc diff --git a/libc/src/ctype/isblank.h b/libc/src/ctype/isblank.h new file mode 100644 index 0000000000000..0554322d08251 --- /dev/null +++ b/libc/src/ctype/isblank.h @@ -0,0 +1,18 @@ +//===-- Implementation header for isblank -------------------------*-C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_CTYPE_ISBLANK_H +#define LLVM_LIBC_SRC_CTYPE_ISBLANK_H + +namespace __llvm_libc { + +int isblank(int c); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_CTYPE_ISBLANK_H diff --git a/libc/src/ctype/iscntrl.cpp b/libc/src/ctype/iscntrl.cpp new file mode 100644 index 0000000000000..06ee7cc0d9703 --- /dev/null +++ b/libc/src/ctype/iscntrl.cpp @@ -0,0 +1,22 @@ +//===-- Implementation of iscntrl------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/ctype/iscntrl.h" + +#include "src/__support/common.h" + +namespace __llvm_libc { + +// TODO: Currently restricted to default locale. +// These should be extended using locale information. +int LLVM_LIBC_ENTRYPOINT(iscntrl)(int c) { + const unsigned char ch = c; + return ch < 0x20 || ch == 0x7f; +} + +} // namespace __llvm_libc diff --git a/libc/src/ctype/iscntrl.h b/libc/src/ctype/iscntrl.h new file mode 100644 index 0000000000000..26f094053a28a --- /dev/null +++ b/libc/src/ctype/iscntrl.h @@ -0,0 +1,18 @@ +//===-- Implementation header for iscntrl -------------------------*-C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_CTYPE_ISCNTRL_H +#define LLVM_LIBC_SRC_CTYPE_ISCNTRL_H + +namespace __llvm_libc { + +int iscntrl(int c); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_CTYPE_ISCNTRL_H diff --git a/libc/src/ctype/isgraph.cpp b/libc/src/ctype/isgraph.cpp new file mode 100644 index 0000000000000..c7a488cbfdeab --- /dev/null +++ b/libc/src/ctype/isgraph.cpp @@ -0,0 +1,20 @@ +//===-- Implementation of isgraph------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/ctype/isgraph.h" + +#include "src/__support/common.h" +#include "src/ctype/ctype_utils.h" + +namespace __llvm_libc { + +// TODO: Currently restricted to default locale. +// These should be extended using locale information. +int LLVM_LIBC_ENTRYPOINT(isgraph)(int c) { return internal::isgraph(c); } + +} // namespace __llvm_libc diff --git a/libc/src/ctype/isgraph.h b/libc/src/ctype/isgraph.h new file mode 100644 index 0000000000000..421d0ffc4488b --- /dev/null +++ b/libc/src/ctype/isgraph.h @@ -0,0 +1,18 @@ +//===-- Implementation header for isgraph -------------------------*-C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_CTYPE_ISGRAPH_H +#define LLVM_LIBC_SRC_CTYPE_ISGRAPH_H + +namespace __llvm_libc { + +int isgraph(int c); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_CTYPE_ISGRAPH_H diff --git a/libc/src/ctype/ispunct.cpp b/libc/src/ctype/ispunct.cpp new file mode 100644 index 0000000000000..a810c6471e796 --- /dev/null +++ b/libc/src/ctype/ispunct.cpp @@ -0,0 +1,22 @@ +//===-- Implementation of ispunct------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/ctype/ispunct.h" + +#include "src/__support/common.h" +#include "src/ctype/ctype_utils.h" + +namespace __llvm_libc { + +// TODO: Currently restricted to default locale. +// These should be extended using locale information. +int LLVM_LIBC_ENTRYPOINT(ispunct)(int c) { + return !internal::isalnum(c) && internal::isgraph(c); +} + +} // namespace __llvm_libc diff --git a/libc/src/ctype/ispunct.h b/libc/src/ctype/ispunct.h new file mode 100644 index 0000000000000..23cc08a0bac9c --- /dev/null +++ b/libc/src/ctype/ispunct.h @@ -0,0 +1,18 @@ +//===-- Implementation header for ispunct -------------------------*-C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_CTYPE_ISPUNCT_H +#define LLVM_LIBC_SRC_CTYPE_ISPUNCT_H + +namespace __llvm_libc { + +int ispunct(int c); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_CTYPE_ISPUNCT_H diff --git a/libc/test/src/ctype/CMakeLists.txt b/libc/test/src/ctype/CMakeLists.txt index c9959465c697c..3adf5739d72a5 100644 --- a/libc/test/src/ctype/CMakeLists.txt +++ b/libc/test/src/ctype/CMakeLists.txt @@ -20,6 +20,26 @@ add_libc_unittest( libc.src.ctype.isalpha ) +add_libc_unittest( + isblank + SUITE + libc_ctype_unittests + SRCS + isblank_test.cpp + DEPENDS + libc.src.ctype.isblank +) + +add_libc_unittest( + iscntrl + SUITE + libc_ctype_unittests + SRCS + iscntrl_test.cpp + DEPENDS + libc.src.ctype.iscntrl +) + add_libc_unittest( isdigit SUITE @@ -30,6 +50,16 @@ add_libc_unittest( libc.src.ctype.isdigit ) +add_libc_unittest( + isgraph + SUITE + libc_ctype_unittests + SRCS + isgraph_test.cpp + DEPENDS + libc.src.ctype.isgraph +) + add_libc_unittest( islower SUITE @@ -40,6 +70,16 @@ add_libc_unittest( libc.src.ctype.islower ) +add_libc_unittest( + ispunct + SUITE + libc_ctype_unittests + SRCS + ispunct_test.cpp + DEPENDS + libc.src.ctype.ispunct +) + add_libc_unittest( isupper SUITE diff --git a/libc/test/src/ctype/isblank_test.cpp b/libc/test/src/ctype/isblank_test.cpp new file mode 100644 index 0000000000000..f024ef67f9f62 --- /dev/null +++ b/libc/test/src/ctype/isblank_test.cpp @@ -0,0 +1,21 @@ +//===-- Unittests for isblank----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/ctype/isblank.h" +#include "utils/UnitTest/Test.h" + +TEST(IsBlank, DefaultLocale) { + // Loops through all characters, verifying that space and horizontal tab + // return a non-zero integer and everything else returns zero. + for (int ch = 0; ch < 255; ++ch) { + if (ch == ' ' || ch == '\t') + EXPECT_NE(__llvm_libc::isblank(ch), 0); + else + EXPECT_EQ(__llvm_libc::isblank(ch), 0); + } +} diff --git a/libc/test/src/ctype/iscntrl_test.cpp b/libc/test/src/ctype/iscntrl_test.cpp new file mode 100644 index 0000000000000..5af7457cbda44 --- /dev/null +++ b/libc/test/src/ctype/iscntrl_test.cpp @@ -0,0 +1,21 @@ +//===-- Unittests for iscntrl----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/ctype/iscntrl.h" +#include "utils/UnitTest/Test.h" + +TEST(IsCntrl, DefaultLocale) { + // Loops through all characters, verifying that control characters + // return a non-zero integer, all others return zero. + for (int ch = 0; ch < 255; ++ch) { + if ((0 <= ch && ch <= 0x1f /*US*/) || ch == 0x7f /*DEL*/) + EXPECT_NE(__llvm_libc::iscntrl(ch), 0); + else + EXPECT_EQ(__llvm_libc::iscntrl(ch), 0); + } +} diff --git a/libc/test/src/ctype/isgraph_test.cpp b/libc/test/src/ctype/isgraph_test.cpp new file mode 100644 index 0000000000000..1ed1ec7145f66 --- /dev/null +++ b/libc/test/src/ctype/isgraph_test.cpp @@ -0,0 +1,21 @@ +//===-- Unittests for isgraph----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/ctype/isgraph.h" +#include "utils/UnitTest/Test.h" + +TEST(IsGraph, DefaultLocale) { + // Loops through all characters, verifying that graphical characters + // return a non-zero integer, everything else returns zero. + for (int ch = 0; ch < 255; ++ch) { + if ('!' <= ch && ch <= '~') // A-Z, a-z, 0-9, punctuation. + EXPECT_NE(__llvm_libc::isgraph(ch), 0); + else + EXPECT_EQ(__llvm_libc::isgraph(ch), 0); + } +} diff --git a/libc/test/src/ctype/ispunct_test.cpp b/libc/test/src/ctype/ispunct_test.cpp new file mode 100644 index 0000000000000..07e83fb36c7cd --- /dev/null +++ b/libc/test/src/ctype/ispunct_test.cpp @@ -0,0 +1,34 @@ +//===-- Unittests for ispunct----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/ctype/ispunct.h" +#include "utils/UnitTest/Test.h" + +// Helper function to mark the sections of the ASCII table that are +// punctuation characters. These are listed below: +// Decimal | Symbol +// ----------------------------------------- +// 33 - 47 | ! " $ % & ' ( ) * + , - . / +// 58 - 64 | : ; < = > ? @ +// 91 - 96 | [ \ ] ^ _ ` +// 123 - 126 | { | } ~ +static inline int is_punctuation_character(int c) { + return ('!' <= c && c <= '/') || (':' <= c && c <= '@') || + ('[' <= c && c <= '`') || ('{' <= c && c <= '~'); +} + +TEST(IsPunct, DefaultLocale) { + // Loops through all characters, verifying that punctuation characters + // return a non-zero integer, and everything else returns zero. + for (int ch = 0; ch < 255; ++ch) { + if (is_punctuation_character(ch)) + EXPECT_NE(__llvm_libc::ispunct(ch), 0); + else + EXPECT_EQ(__llvm_libc::ispunct(ch), 0); + } +}