| //===----------------------------------------------------------------------===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// Implementation of regerror. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #include "src/regex/regerror.h" |
| |
| #include "hdr/regex_macros.h" |
| #include "src/__support/CPP/string_view.h" |
| #include "src/__support/common.h" |
| #include "src/__support/macros/config.h" |
| #include "src/string/memory_utils/inline_memcpy.h" |
| |
| namespace LIBC_NAMESPACE_DECL { |
| |
| LLVM_LIBC_FUNCTION(size_t, regerror, |
| (int errcode, const regex_t *__restrict preg, |
| char *__restrict errbuf, size_t errbuf_size)) { |
| (void)preg; // preg is reserved for implementation-specific messages. |
| |
| cpp::string_view msg = [errcode]() -> const char * { |
| switch (errcode) { |
| case 0: |
| return "Success"; |
| case REG_NOMATCH: |
| return "No match"; |
| case REG_BADPAT: |
| return "Invalid regular expression"; |
| case REG_ECOLLATE: |
| return "Invalid collating element"; |
| case REG_ECTYPE: |
| return "Invalid character class"; |
| case REG_EESCAPE: |
| return "Trailing backslash"; |
| case REG_ESUBREG: |
| return "Invalid backreference"; |
| case REG_EBRACK: |
| return "Missing ']'"; |
| case REG_EPAREN: |
| return "Missing ')'"; |
| case REG_EBRACE: |
| return "Missing '}'"; |
| case REG_BADBR: |
| return "Invalid repetition count"; |
| case REG_ERANGE: |
| return "Invalid range end"; |
| case REG_ESPACE: |
| return "Out of memory"; |
| case REG_BADRPT: |
| return "Invalid preceding expression"; |
| default: |
| return "Unknown error"; |
| } |
| }(); |
| |
| size_t msg_len = msg.size() + 1; // include NUL |
| |
| if (errbuf_size > 0 && errbuf) { |
| size_t copy_len = msg_len < errbuf_size ? msg_len : errbuf_size; |
| inline_memcpy(errbuf, msg.data(), copy_len - 1); |
| errbuf[copy_len - 1] = '\0'; |
| } |
| // POSIX requires returning the size needed to hold the full NUL-terminated |
| // string, even if it was truncated in the buffer. |
| return msg_len; |
| } |
| |
| } // namespace LIBC_NAMESPACE_DECL |