diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -2,8 +2,12 @@ # 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 --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -90,8 +90,12 @@ 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 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -5,8 +5,12 @@ # 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 --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -56,16 +56,36 @@ 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 --- a/libc/src/ctype/CMakeLists.txt +++ b/libc/src/ctype/CMakeLists.txt @@ -24,6 +24,22 @@ .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 @@ .ctype_utils ) +add_entrypoint_object( + isgraph + SRCS + isgraph.cpp + HDRS + isgraph.h + DEPENDS + .ctype_utils +) + add_entrypoint_object( islower SRCS @@ -42,6 +68,16 @@ 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 --- a/libc/src/ctype/ctype_utils.h +++ b/libc/src/ctype/ctype_utils.h @@ -18,15 +18,13 @@ // 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 --- a/libc/src/ctype/isalnum.cpp +++ b/libc/src/ctype/isalnum.cpp @@ -15,8 +15,6 @@ // 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.h b/libc/src/ctype/isblank.h new file mode 100644 --- /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/isalnum.cpp b/libc/src/ctype/isblank.cpp copy from libc/src/ctype/isalnum.cpp copy to libc/src/ctype/isblank.cpp --- a/libc/src/ctype/isalnum.cpp +++ b/libc/src/ctype/isblank.cpp @@ -1,4 +1,4 @@ -//===-- Implementation of isalnum------------------------------------------===// +//===-- 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. @@ -6,8 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/ctype/isalnum.h" -#include "src/ctype/ctype_utils.h" +#include "src/ctype/isblank.h" #include "src/__support/common.h" @@ -15,8 +14,9 @@ // 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(isblank)(int c) { + const unsigned char ch = c; + return ch == ' ' || ch == '\t'; } } // namespace __llvm_libc diff --git a/libc/src/ctype/iscntrl.h b/libc/src/ctype/iscntrl.h new file mode 100644 --- /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/isalnum.cpp b/libc/src/ctype/iscntrl.cpp copy from libc/src/ctype/isalnum.cpp copy to libc/src/ctype/iscntrl.cpp --- a/libc/src/ctype/isalnum.cpp +++ b/libc/src/ctype/iscntrl.cpp @@ -1,4 +1,4 @@ -//===-- Implementation of isalnum------------------------------------------===// +//===-- 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. @@ -6,8 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "src/ctype/isalnum.h" -#include "src/ctype/ctype_utils.h" +#include "src/ctype/iscntrl.h" #include "src/__support/common.h" @@ -15,8 +14,9 @@ // 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(iscntrl)(int c) { + const unsigned char ch = c; + return ch < 0x20 || ch == 0x7f; } } // namespace __llvm_libc diff --git a/libc/src/ctype/isgraph.h b/libc/src/ctype/isgraph.h new file mode 100644 --- /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/isalnum.cpp b/libc/src/ctype/isgraph.cpp copy from libc/src/ctype/isalnum.cpp copy to libc/src/ctype/isgraph.cpp --- a/libc/src/ctype/isalnum.cpp +++ b/libc/src/ctype/isgraph.cpp @@ -1,4 +1,4 @@ -//===-- Implementation of isalnum------------------------------------------===// +//===-- 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. @@ -6,17 +6,15 @@ // //===----------------------------------------------------------------------===// -#include "src/ctype/isalnum.h" -#include "src/ctype/ctype_utils.h" +#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(isalnum)(int c) { - return internal::isalpha(c) || internal::isdigit(c); -} +int LLVM_LIBC_ENTRYPOINT(isgraph)(int c) { return internal::isgraph(c); } } // namespace __llvm_libc diff --git a/libc/src/ctype/ispunct.h b/libc/src/ctype/ispunct.h new file mode 100644 --- /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/src/ctype/isalnum.cpp b/libc/src/ctype/ispunct.cpp copy from libc/src/ctype/isalnum.cpp copy to libc/src/ctype/ispunct.cpp --- a/libc/src/ctype/isalnum.cpp +++ b/libc/src/ctype/ispunct.cpp @@ -1,4 +1,4 @@ -//===-- Implementation of isalnum------------------------------------------===// +//===-- 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. @@ -6,17 +6,17 @@ // //===----------------------------------------------------------------------===// -#include "src/ctype/isalnum.h" -#include "src/ctype/ctype_utils.h" +#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(isalnum)(int c) { - return internal::isalpha(c) || internal::isdigit(c); +int LLVM_LIBC_ENTRYPOINT(ispunct)(int c) { + return !internal::isalnum(c) && internal::isgraph(c); } } // namespace __llvm_libc diff --git a/libc/test/src/ctype/CMakeLists.txt b/libc/test/src/ctype/CMakeLists.txt --- a/libc/test/src/ctype/CMakeLists.txt +++ b/libc/test/src/ctype/CMakeLists.txt @@ -20,6 +20,26 @@ 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 @@ 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 @@ 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 --- /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 --- /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 --- /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 --- /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); + } +}