| //===----------------------------------------------------------------------===// | |
| // | |
| // 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 | |
| /// This file contains the implementation of FileMode class. This is the class | |
| /// that handles everything related to a file's mode. | |
| /// | |
| //===----------------------------------------------------------------------===// | |
| #ifndef LLVM_LIBC_SRC___SUPPORT_FILE_FILE_MODE_H | |
| #define LLVM_LIBC_SRC___SUPPORT_FILE_FILE_MODE_H | |
| #include "hdr/stdint_proxy.h" | |
| #include "src/__support/macros/attributes.h" | |
| #include "src/__support/macros/config.h" | |
| namespace LIBC_NAMESPACE_DECL { | |
| // FileMode class handles everything regarding the mode of the file, be it | |
| // opening mode or content type. | |
| class FileMode { | |
| public: | |
| // FileMode constructor accepts the mode string as an argument. | |
| // It performs validation against several rules and records the `file_mode` | |
| // property to the specific mode. | |
| constexpr FileMode(const char *mode) : file_mode_(0) { | |
| // First character in |mode| should be 'a', 'r' or 'w'. | |
| if (*mode != 'a' && *mode != 'r' && *mode != 'w') | |
| return; | |
| // There should be exactly one main mode ('a', 'r' or 'w') character. | |
| // If there are more than one main mode characters listed, then | |
| // we will consider |mode| as incorrect and set the file's mode to zero | |
| // meaning the file's mode is in an invalid state.; | |
| int main_mode_count = 0; | |
| for (; *mode != '\0'; ++mode) { | |
| switch (*mode) { | |
| case 'r': | |
| file_mode_ |= static_cast<Mode>(OpenMode::READ); | |
| ++main_mode_count; | |
| break; | |
| case 'w': | |
| file_mode_ |= static_cast<Mode>(OpenMode::WRITE); | |
| ++main_mode_count; | |
| break; | |
| case '+': | |
| file_mode_ |= static_cast<Mode>(OpenMode::PLUS); | |
| break; | |
| case 'b': | |
| file_mode_ |= static_cast<Mode>(ContentType::BINARY); | |
| break; | |
| case 'a': | |
| file_mode_ |= static_cast<Mode>(OpenMode::APPEND); | |
| ++main_mode_count; | |
| break; | |
| case 'x': | |
| file_mode_ |= static_cast<Mode>(CreateType::EXCLUSIVE); | |
| break; | |
| default: | |
| file_mode_ = 0; | |
| } | |
| } | |
| if (main_mode_count != 1) | |
| file_mode_ = 0; | |
| } | |
| static const FileMode APPEND_MODE; | |
| static const FileMode READ_MODE; | |
| static const FileMode WRITE_MODE; | |
| constexpr bool write_allowed() const { | |
| return is_write() || is_append() || is_update(); | |
| } | |
| constexpr bool read_allowed() const { return is_read() || is_update(); } | |
| constexpr bool is_valid() const { return file_mode_ != 0; } | |
| constexpr bool is_append() const { | |
| return (file_mode_ & static_cast<Mode>(OpenMode::APPEND)) != 0; | |
| } | |
| constexpr bool is_update() const { | |
| return (file_mode_ & static_cast<Mode>(OpenMode::PLUS)) != 0; | |
| } | |
| constexpr bool is_write() const { | |
| return (file_mode_ & static_cast<Mode>(OpenMode::WRITE)) != 0; | |
| } | |
| constexpr bool is_read() const { | |
| return (file_mode_ & static_cast<Mode>(OpenMode::READ)) != 0; | |
| } | |
| constexpr bool is_binary_format() const { | |
| return (file_mode_ & static_cast<Mode>(ContentType::BINARY)) != 0; | |
| } | |
| // checks if a file was created for writing | |
| constexpr bool is_exclusive_create() const { | |
| return (file_mode_ & static_cast<Mode>(CreateType::EXCLUSIVE)) != 0; | |
| } | |
| private: | |
| // Mode is a generic or abstract mode bit for all kinds of modes | |
| // (open-mode, 'content-mode', 'create-modes') | |
| using Mode = uint32_t; | |
| // Denotes the mode of the file. | |
| // | |
| // The three different types of flags below are to be used with '|' operator. | |
| // Their values correspond to mutually exclusive bits in a 32-bit unsigned | |
| // integer value. A flag set can include both READ and WRITE if the file | |
| // is opened in update mode (ie. if the file was opened with a '+' the mode | |
| // string.) | |
| enum class OpenMode : Mode { | |
| READ = 0x1, | |
| WRITE = 0x2, | |
| APPEND = 0x4, | |
| PLUS = 0x8, | |
| }; | |
| // Denotes a file opened in binary mode (which is specified by including | |
| // the 'b' character in the mode string.) | |
| enum class ContentType : Mode { | |
| BINARY = 0x10, | |
| }; | |
| // Denotes a file to be created for writing. | |
| enum class CreateType : Mode { | |
| EXCLUSIVE = 0x100, | |
| }; | |
| // This property tracks the mode for the particular file instance (i.e | |
| // currently opened file) | |
| Mode file_mode_; | |
| }; | |
| LIBC_INLINE_VAR constexpr FileMode FileMode::APPEND_MODE("a"); | |
| LIBC_INLINE_VAR constexpr FileMode FileMode::READ_MODE("r"); | |
| LIBC_INLINE_VAR constexpr FileMode FileMode::WRITE_MODE("w"); | |
| } // namespace LIBC_NAMESPACE_DECL | |
| #endif // LLVM_LIBC_SRC___SUPPORT_FILE_FILE_MODE_H |