mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 21:07:26 +02:00
Add file_stdio and File concept
This commit is contained in:
@ -1,3 +1,9 @@
|
||||
Version 74:
|
||||
|
||||
* Add file_stdio and File concept
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Version 73:
|
||||
|
||||
* Jamroot tweak
|
||||
|
@ -60,6 +60,7 @@
|
||||
[def __DynamicBuffer__ [link beast.concept.DynamicBuffer [*DynamicBuffer]]]
|
||||
[def __Fields__ [link beast.concept.Fields [*Fields]]]
|
||||
[def __FieldsReader__ [link beast.concept.FieldsReader [*FieldsReader]]]
|
||||
[def __File__ [link beast.concept.File [*File]]]
|
||||
[def __Stream__ [link beast.concept.streams [*Stream]]]
|
||||
[def __SyncStream__ [link beast.concept.streams.SyncStream [*SyncStream]]]
|
||||
|
||||
@ -77,13 +78,14 @@
|
||||
[def __static_buffer__ [link beast.ref.beast__static_buffer `static_buffer`]]
|
||||
[def __static_buffer_n__ [link beast.ref.beast__static_buffer_n `static_buffer_n`]]
|
||||
|
||||
[import ../example/doc/http_examples.hpp]
|
||||
[import ../example/echo-op/echo_op.cpp]
|
||||
[import ../example/common/detect_ssl.hpp]
|
||||
[import ../example/common/file_body.hpp]
|
||||
[import ../example/doc/http_examples.hpp]
|
||||
[import ../example/echo-op/echo_op.cpp]
|
||||
[import ../example/http-client/http_client.cpp]
|
||||
[import ../example/websocket-client/websocket_client.cpp]
|
||||
|
||||
|
||||
[import ../test/exemplars.cpp]
|
||||
[import ../test/core/doc_snippets.cpp]
|
||||
[import ../test/http/doc_snippets.cpp]
|
||||
|
@ -13,6 +13,7 @@ This section describes all of the concepts defined by the library.
|
||||
[include concept/BodyReader.qbk]
|
||||
[include concept/BodyWriter.qbk]
|
||||
[include concept/BufferSequence.qbk]
|
||||
[include concept/File.qbk]
|
||||
[include concept/DynamicBuffer.qbk]
|
||||
[include concept/Fields.qbk]
|
||||
[include concept/FieldsReader.qbk]
|
||||
|
173
doc/concept/File.qbk
Normal file
173
doc/concept/File.qbk
Normal file
@ -0,0 +1,173 @@
|
||||
[/
|
||||
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:File File]
|
||||
|
||||
The [*File] concept abstracts access to files in the underlying file system.
|
||||
To support other platform interfaces, users may author their own [*File]
|
||||
types which meet these requirements.
|
||||
|
||||
In this table:
|
||||
|
||||
* `F` is a [*File] type
|
||||
* `f` is an instance of `F`
|
||||
* `p` is a value of type `char const*` which points to a null
|
||||
terminated utf-8 encoded string.
|
||||
* `m` is an instance of [link beast.ref.beast__file_mode `file_mode`]
|
||||
* `n` is a number of bytes, convertible to `std::size_t`
|
||||
* `o` is a byte offset in the file, convertible to `std::uint64_t`
|
||||
* `b` is any non-const pointer to memory
|
||||
* `c` is any possibly-const pointer to memory
|
||||
* `ec` is a reference of type [link beast.ref.beast__error_code `error_code`]
|
||||
|
||||
[heading Associated Types]
|
||||
|
||||
* [link beast.ref.beast__file_mode `file_mode`]
|
||||
* [link beast.ref.beast__is_file `is_file`]
|
||||
|
||||
[heading File Requirements]
|
||||
[table Valid Expressions
|
||||
[[Operation] [Return Type] [Semantics, Pre/Post-conditions]]
|
||||
[
|
||||
[`F()`]
|
||||
[ ]
|
||||
[
|
||||
Default constructable
|
||||
]
|
||||
]
|
||||
[
|
||||
[`f.~F()`]
|
||||
[ ]
|
||||
[
|
||||
Destructible.
|
||||
If `f` refers to an open file, it is first closed
|
||||
as if by a call to `close` with the error ignored.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`f.is_open()`]
|
||||
[`bool`]
|
||||
[
|
||||
Returns `true` if `f` refers to an open file, `false` otherwise.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`f.close(ec)`]
|
||||
[]
|
||||
[
|
||||
If `f` refers to an open file, thie function attempts to
|
||||
close the file.
|
||||
Regardless of whether an error occurs or not, a subsequent
|
||||
call to `f.is_open()` will return `false`.
|
||||
The function will ensure that `!ec` is `true` if there was
|
||||
no error or set to the appropriate error code if an error
|
||||
occurred.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`f.open(p,m,ec)`]
|
||||
[]
|
||||
[
|
||||
Attempts to open the file at the path specified by `p`
|
||||
with the mode specified by `m`.
|
||||
Upon success, a subsequent call to `f.is_open()` will
|
||||
return `true`.
|
||||
If `f` refers to an open file, it is first closed
|
||||
as if by a call to `close` with the error ignored.
|
||||
The function will ensure that `!ec` is `true` if there was
|
||||
no error or set to the appropriate error code if an error
|
||||
occurred.
|
||||
|
||||
]
|
||||
]
|
||||
[
|
||||
[`f.size(ec)`]
|
||||
[`std::uint64_t`]
|
||||
[
|
||||
If `f` refers to an open file, this function attempts to
|
||||
determine the file size and return its value.
|
||||
If `f` does not refer to an open file, the function will
|
||||
set `ec` to `errc::invalid_argument` and return 0.
|
||||
The function will ensure that `!ec` is `true` if there was
|
||||
no error or set to the appropriate error code if an error
|
||||
occurred.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`f.pos(ec)`]
|
||||
[`std::uint64_t`]
|
||||
[
|
||||
If `f` refers to an open file, this function attempts to
|
||||
determine the current file offset and return it.
|
||||
If `f` does not refer to an open file, the function will
|
||||
set `ec` to `errc::invalid_argument` and return 0.
|
||||
The function will ensure that `!ec` is `true` if there was
|
||||
no error or set to the appropriate error code if an error
|
||||
occurred.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`f.seek(o,ec)`]
|
||||
[]
|
||||
[
|
||||
Attempts to reposition the current file offset to the value
|
||||
`o`, which represents a byte offset relative to the beginning
|
||||
of the file.
|
||||
If `f` does not refer to an open file, the function will
|
||||
set `ec` to `errc::invalid_argument` and return immediately.
|
||||
The function will ensure that `!ec` is `true` if there was
|
||||
no error or set to the appropriate error code if an error
|
||||
occurred.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`f.read(b,n,ec)`]
|
||||
[`std::size_t`]
|
||||
[
|
||||
Attempts to read `n` bytes starting at the current file offset
|
||||
from the open file referred to by `f`.
|
||||
Bytes read are stored in the memory buffer at address `b` which
|
||||
must be at least `n` bytes in size.
|
||||
The function advances the file offset by the amount read, and
|
||||
returns the number of bytes actually read, which may be less
|
||||
than `n`.
|
||||
If `f` does not refer to an open file, the function will
|
||||
set `ec` to `errc::invalid_argument` and return immediately.
|
||||
The function will ensure that `!ec` is `true` if there was
|
||||
no error or set to the appropriate error code if an error
|
||||
occurred.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`f.write(c,n,ec)`]
|
||||
[`std::size_t`]
|
||||
[
|
||||
Attempts to write `n` bytes from the buffer pointed to by `c` to
|
||||
the current file offset of the open file referred to by `f`.
|
||||
The memory buffer at `c` must point to storage of at least `n`
|
||||
bytes meant to be copied to the file.
|
||||
The function advances the file offset by the amount written,
|
||||
and returns the number of bytes actually written, which may be
|
||||
less than `n`.
|
||||
If `f` does not refer to an open file, the function will
|
||||
set `ec` to `errc::invalid_argument` and return immediately.
|
||||
The function will ensure that `!ec` is `true` if there was
|
||||
no error or set to the appropriate error code if an error
|
||||
occurred.
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
[heading Exemplar]
|
||||
|
||||
[concept_File]
|
||||
|
||||
[heading Models]
|
||||
|
||||
* [link beast.ref.beast__file_stdio `file_stdio`]
|
||||
|
||||
[endsect]
|
@ -173,11 +173,13 @@
|
||||
<member><link linkend="beast.ref.beast__error_category">error_category</link></member>
|
||||
<member><link linkend="beast.ref.beast__error_code">error_code</link></member>
|
||||
<member><link linkend="beast.ref.beast__error_condition">error_condition</link></member>
|
||||
<member><link linkend="beast.ref.beast__file">file</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3"> </bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.beast__file_stdio">file_stdio</link></member>
|
||||
<member><link linkend="beast.ref.beast__flat_buffer">flat_buffer</link></member>
|
||||
<member><link linkend="beast.ref.beast__handler_alloc">handler_alloc</link></member>
|
||||
<member><link linkend="beast.ref.beast__handler_ptr">handler_ptr</link></member>
|
||||
@ -211,6 +213,7 @@
|
||||
<bridgehead renderas="sect3">Constants</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.beast__errc">errc</link></member>
|
||||
<member><link linkend="beast.ref.beast__file_mode">file_mode</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
@ -224,6 +227,7 @@
|
||||
<member><link linkend="beast.ref.beast__is_completion_handler">is_completion_handler</link></member>
|
||||
<member><link linkend="beast.ref.beast__is_const_buffer_sequence">is_const_buffer_sequence</link></member>
|
||||
<member><link linkend="beast.ref.beast__is_dynamic_buffer">is_dynamic_buffer</link></member>
|
||||
<member><link linkend="beast.ref.beast__is_file">is_file</link></member>
|
||||
<member><link linkend="beast.ref.beast__is_mutable_buffer_sequence">is_mutable_buffer_sequence</link></member>
|
||||
<member><link linkend="beast.ref.beast__is_sync_read_stream">is_sync_read_stream</link></member>
|
||||
<member><link linkend="beast.ref.beast__is_sync_stream">is_sync_stream</link></member>
|
||||
@ -236,6 +240,7 @@
|
||||
<member><link linkend="beast.concept.streams.AsyncStream">AsyncStream</link></member>
|
||||
<member><link linkend="beast.concept.BufferSequence">BufferSequence</link></member>
|
||||
<member><link linkend="beast.concept.DynamicBuffer">DynamicBuffer</link></member>
|
||||
<member><link linkend="beast.concept.File">File</link></member>
|
||||
<member><link linkend="beast.concept.streams.Stream">Stream</link></member>
|
||||
<member><link linkend="beast.concept.streams.SyncStream">SyncStream</link></member>
|
||||
</simplelist>
|
||||
|
@ -19,6 +19,9 @@
|
||||
#include <beast/core/consuming_buffers.hpp>
|
||||
#include <beast/core/drain_buffer.hpp>
|
||||
#include <beast/core/error.hpp>
|
||||
#include <beast/core/file.hpp>
|
||||
#include <beast/core/file_base.hpp>
|
||||
#include <beast/core/file_stdio.hpp>
|
||||
#include <beast/core/flat_buffer.hpp>
|
||||
#include <beast/core/handler_alloc.hpp>
|
||||
#include <beast/core/handler_ptr.hpp>
|
||||
|
25
include/beast/core/file.hpp
Normal file
25
include/beast/core/file.hpp
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_CORE_FILE_HPP
|
||||
#define BEAST_CORE_FILE_HPP
|
||||
|
||||
#include <beast/core/file_base.hpp>
|
||||
#include <beast/core/file_stdio.hpp>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** An implementation of File.
|
||||
|
||||
This alias is set to the best available implementation
|
||||
of @b File given the platform and build settings.
|
||||
*/
|
||||
using file = file_stdio;
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
87
include/beast/core/file_base.hpp
Normal file
87
include/beast/core/file_base.hpp
Normal file
@ -0,0 +1,87 @@
|
||||
//
|
||||
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_CORE_FILE_BASE_HPP
|
||||
#define BEAST_CORE_FILE_BASE_HPP
|
||||
|
||||
#include <beast/core/string.hpp>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/// The type of file path used by the library
|
||||
using file_path = string_view;
|
||||
|
||||
/** File open modes
|
||||
|
||||
These modes are used when opening files using
|
||||
instances of the @b File concept.
|
||||
|
||||
@see file_stdio
|
||||
*/
|
||||
enum class file_mode
|
||||
{
|
||||
/// Random reading
|
||||
read,
|
||||
|
||||
/// Sequential reading
|
||||
scan,
|
||||
|
||||
/** Random writing to a new or truncated file
|
||||
|
||||
@li If the file does not exist, it is created.
|
||||
|
||||
@li If the file exists, it is truncated to
|
||||
zero size upon opening.
|
||||
*/
|
||||
write,
|
||||
|
||||
/** Random writing to new file only
|
||||
|
||||
If the file exists, an error is generated.
|
||||
*/
|
||||
write_new,
|
||||
|
||||
/** Random writing to existing file
|
||||
|
||||
If the file does not exist, an error is generated.
|
||||
*/
|
||||
write_existing,
|
||||
|
||||
/** Appending to a new or truncated file
|
||||
|
||||
The current file position shall be set to the end of
|
||||
the file prior to each write.
|
||||
|
||||
@li If the file does not exist, it is created.
|
||||
|
||||
@li If the file exists, it is truncated to
|
||||
zero size upon opening.
|
||||
*/
|
||||
append,
|
||||
|
||||
/** Appending to a new file only
|
||||
|
||||
The current file position shall be set to the end of
|
||||
the file prior to each write.
|
||||
|
||||
If the file exists, an error is generated.
|
||||
*/
|
||||
append_new,
|
||||
|
||||
/** Appending to an existing file
|
||||
|
||||
The current file position shall be set to the end of
|
||||
the file prior to each write.
|
||||
|
||||
If the file does not exist, an error is generated.
|
||||
*/
|
||||
append_existing
|
||||
};
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
153
include/beast/core/file_stdio.hpp
Normal file
153
include/beast/core/file_stdio.hpp
Normal file
@ -0,0 +1,153 @@
|
||||
//
|
||||
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_CORE_FILE_STDIO_HPP
|
||||
#define BEAST_CORE_FILE_STDIO_HPP
|
||||
|
||||
#include <beast/core/error.hpp>
|
||||
#include <beast/core/file_base.hpp>
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** An implementation of File which uses cstdio.
|
||||
|
||||
This class implements a file using the interfaces present
|
||||
in the C++ Standard Library, in `<stdio>`.
|
||||
*/
|
||||
class file_stdio
|
||||
{
|
||||
FILE* f_ = nullptr;
|
||||
|
||||
public:
|
||||
/** The type of the underlying file handle.
|
||||
|
||||
This is platform-specific.
|
||||
*/
|
||||
using native_handle_type = FILE*;
|
||||
|
||||
/** Destructor
|
||||
|
||||
If the file is open it is first closed.
|
||||
*/
|
||||
~file_stdio();
|
||||
|
||||
/** Constructor
|
||||
|
||||
There is no open file initially.
|
||||
*/
|
||||
file_stdio() = default;
|
||||
|
||||
/** Constructor
|
||||
|
||||
The moved-from object behaves as if default constructed.
|
||||
*/
|
||||
file_stdio(file_stdio&& other);
|
||||
|
||||
/** Assignment
|
||||
|
||||
The moved-from object behaves as if default constructed.
|
||||
*/
|
||||
file_stdio& operator=(file_stdio&& other);
|
||||
|
||||
/// Returns the native handle associated with the file.
|
||||
FILE*
|
||||
native_handle() const
|
||||
{
|
||||
return f_;
|
||||
}
|
||||
|
||||
/** Set the native handle associated with the file.
|
||||
|
||||
If the file is open it is first closed.
|
||||
|
||||
@param f The native file handle to assign.
|
||||
*/
|
||||
void
|
||||
native_handle(FILE* f);
|
||||
|
||||
/// Returns `true` if the file is open
|
||||
bool
|
||||
is_open() const
|
||||
{
|
||||
return f_ != nullptr;
|
||||
}
|
||||
|
||||
/** Close the file if open
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
*/
|
||||
void
|
||||
close(error_code& ec);
|
||||
|
||||
/** Open a file at the given path with the specified mode
|
||||
|
||||
@param path The utf-8 encoded path to the file
|
||||
|
||||
@param mode The file mode to use
|
||||
|
||||
@param ec Set to the error, if any occurred
|
||||
*/
|
||||
void
|
||||
open(char const* path, file_mode mode, error_code& ec);
|
||||
|
||||
/** Return the size of the open file
|
||||
|
||||
@param ec Set to the error, if any occurred
|
||||
|
||||
@return The size in bytes
|
||||
*/
|
||||
std::uint64_t
|
||||
size(error_code& ec) const;
|
||||
|
||||
/** Return the current position in the open file
|
||||
|
||||
@param ec Set to the error, if any occurred
|
||||
|
||||
@return The offset in bytes from the beginning of the file
|
||||
*/
|
||||
std::uint64_t
|
||||
pos(error_code& ec) const;
|
||||
|
||||
/** Adjust the current position in the open file
|
||||
|
||||
@param offset The offset in bytes from the beginning of the file
|
||||
|
||||
@param ec Set to the error, if any occurred
|
||||
*/
|
||||
void
|
||||
seek(std::uint64_t offset, error_code& ec);
|
||||
|
||||
/** Read from the open file
|
||||
|
||||
@param buffer The buffer for storing the result of the read
|
||||
|
||||
@param n The number of bytes to read
|
||||
|
||||
@param ec Set to the error, if any occurred
|
||||
*/
|
||||
std::size_t
|
||||
read(void* buffer, std::size_t n, error_code& ec) const;
|
||||
|
||||
/** Write to the open file
|
||||
|
||||
@param buffer The buffer holding the data to write
|
||||
|
||||
@param n The number of bytes to write
|
||||
|
||||
@param ec Set to the error, if any occurred
|
||||
*/
|
||||
std::size_t
|
||||
write(void const* buffer, std::size_t n, error_code& ec);
|
||||
};
|
||||
|
||||
} // beast
|
||||
|
||||
#include <beast/core/impl/file_stdio.ipp>
|
||||
|
||||
#endif
|
225
include/beast/core/impl/file_stdio.ipp
Normal file
225
include/beast/core/impl/file_stdio.ipp
Normal file
@ -0,0 +1,225 @@
|
||||
//
|
||||
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_CORE_IMPL_FILE_STDIO_IPP
|
||||
#define BEAST_CORE_IMPL_FILE_STDIO_IPP
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace beast {
|
||||
|
||||
inline
|
||||
file_stdio::
|
||||
~file_stdio()
|
||||
{
|
||||
if(f_)
|
||||
fclose(f_);
|
||||
}
|
||||
|
||||
inline
|
||||
file_stdio::
|
||||
file_stdio(file_stdio&& other)
|
||||
: f_(other.f_)
|
||||
{
|
||||
other.f_ = nullptr;
|
||||
}
|
||||
|
||||
inline
|
||||
file_stdio&
|
||||
file_stdio::
|
||||
operator=(file_stdio&& other)
|
||||
{
|
||||
if(&other == this)
|
||||
return *this;
|
||||
if(f_)
|
||||
fclose(f_);
|
||||
f_ = other.f_;
|
||||
other.f_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
file_stdio::
|
||||
native_handle(FILE* f)
|
||||
{
|
||||
if(f_)
|
||||
fclose(f_);
|
||||
f_ = f;
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
file_stdio::
|
||||
close(error_code& ec)
|
||||
{
|
||||
if(f_)
|
||||
{
|
||||
int failed = fclose(f_);
|
||||
f_ = nullptr;
|
||||
if(failed)
|
||||
{
|
||||
ec.assign(errno, generic_category());
|
||||
return;
|
||||
}
|
||||
}
|
||||
ec.assign(0, ec.category());
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
file_stdio::
|
||||
open(char const* path, file_mode mode, error_code& ec)
|
||||
{
|
||||
if(f_)
|
||||
{
|
||||
fclose(f_);
|
||||
f_ = nullptr;
|
||||
}
|
||||
char const* s;
|
||||
switch(mode)
|
||||
{
|
||||
default:
|
||||
case file_mode::read: s = "rb"; break;
|
||||
case file_mode::scan: s = "rb"; break;
|
||||
case file_mode::write: s = "wb"; break;
|
||||
case file_mode::write_new: s = "wbx"; break;
|
||||
case file_mode::write_existing: s = "wb"; break;
|
||||
case file_mode::append: s = "ab"; break;
|
||||
case file_mode::append_new: s = "abx"; break;
|
||||
case file_mode::append_existing: s = "ab"; break;
|
||||
}
|
||||
f_ = std::fopen(path, s);
|
||||
if(! f_)
|
||||
{
|
||||
ec.assign(errno, generic_category());
|
||||
return;
|
||||
}
|
||||
ec.assign(0, ec.category());
|
||||
}
|
||||
|
||||
inline
|
||||
std::uint64_t
|
||||
file_stdio::
|
||||
size(error_code& ec) const
|
||||
{
|
||||
if(! f_)
|
||||
{
|
||||
ec.assign(errc::invalid_argument, generic_category());
|
||||
return 0;
|
||||
}
|
||||
long pos = std::ftell(f_);
|
||||
if(pos == -1L)
|
||||
{
|
||||
ec.assign(errno, generic_category());
|
||||
return 0;
|
||||
}
|
||||
int result = std::fseek(f_, 0, SEEK_END);
|
||||
if(result != 0)
|
||||
{
|
||||
ec.assign(errno, generic_category());
|
||||
return 0;
|
||||
}
|
||||
long size = std::ftell(f_);
|
||||
if(size == -1L)
|
||||
{
|
||||
ec.assign(errno, generic_category());
|
||||
std::fseek(f_, pos, SEEK_SET);
|
||||
return 0;
|
||||
}
|
||||
result = std::fseek(f_, pos, SEEK_SET);
|
||||
if(result != 0)
|
||||
ec.assign(errno, generic_category());
|
||||
else
|
||||
ec.assign(0, ec.category());
|
||||
return size;
|
||||
}
|
||||
|
||||
inline
|
||||
std::uint64_t
|
||||
file_stdio::
|
||||
pos(error_code& ec) const
|
||||
{
|
||||
if(! f_)
|
||||
{
|
||||
ec.assign(errc::invalid_argument, generic_category());
|
||||
return 0;
|
||||
}
|
||||
long pos = std::ftell(f_);
|
||||
if(pos == -1L)
|
||||
{
|
||||
ec.assign(errno, generic_category());
|
||||
return 0;
|
||||
}
|
||||
ec.assign(0, ec.category());
|
||||
return pos;
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
file_stdio::
|
||||
seek(std::uint64_t offset, error_code& ec)
|
||||
{
|
||||
if(! f_)
|
||||
{
|
||||
ec.assign(errc::invalid_argument, generic_category());
|
||||
return;
|
||||
}
|
||||
if(offset > (std::numeric_limits<long>::max)())
|
||||
{
|
||||
ec = make_error_code(errc::invalid_seek);
|
||||
return;
|
||||
}
|
||||
int result = std::fseek(f_,
|
||||
static_cast<long>(offset), SEEK_SET);
|
||||
if(result != 0)
|
||||
ec.assign(errno, generic_category());
|
||||
else
|
||||
ec.assign(0, ec.category());
|
||||
}
|
||||
|
||||
inline
|
||||
std::size_t
|
||||
file_stdio::
|
||||
read(void* buffer, std::size_t n, error_code& ec) const
|
||||
{
|
||||
if(! f_)
|
||||
{
|
||||
ec.assign(errc::invalid_argument, generic_category());
|
||||
return 0;
|
||||
}
|
||||
auto nread = std::fread(buffer, 1, n, f_);
|
||||
if(std::ferror(f_))
|
||||
{
|
||||
ec.assign(errno, generic_category());
|
||||
return 0;
|
||||
}
|
||||
return nread;
|
||||
}
|
||||
|
||||
inline
|
||||
std::size_t
|
||||
file_stdio::
|
||||
write(void const* buffer, std::size_t n, error_code& ec)
|
||||
{
|
||||
if(! f_)
|
||||
{
|
||||
ec.assign(errc::invalid_argument, generic_category());
|
||||
return 0;
|
||||
}
|
||||
auto nwritten = std::fwrite(buffer, 1, n, f_);
|
||||
if(std::ferror(f_))
|
||||
{
|
||||
ec.assign(errno, generic_category());
|
||||
return 0;
|
||||
}
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
@ -9,6 +9,7 @@
|
||||
#define BEAST_TYPE_TRAITS_HPP
|
||||
|
||||
#include <beast/config.hpp>
|
||||
#include <beast/core/file_base.hpp>
|
||||
#include <beast/core/detail/type_traits.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <type_traits>
|
||||
@ -558,6 +559,75 @@ using is_sync_stream = std::integral_constant<bool,
|
||||
is_sync_read_stream<T>::value && is_sync_write_stream<T>::value>;
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// File concepts
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Determine if `T` meets the requirements of @b File.
|
||||
|
||||
Metafunctions are used to perform compile time checking of template
|
||||
types. This type will be `std::true_type` if `T` meets the requirements,
|
||||
else the type will be `std::false_type`.
|
||||
|
||||
@par Example
|
||||
|
||||
Use with `static_assert`:
|
||||
|
||||
@code
|
||||
template<class File>
|
||||
void f(File& file)
|
||||
{
|
||||
static_assert(is_file<File>::value,
|
||||
"File requirements not met");
|
||||
...
|
||||
@endcode
|
||||
|
||||
Use with `std::enable_if` (SFINAE):
|
||||
|
||||
@code
|
||||
template<class File>
|
||||
typename std::enable_if<is_file<File>::value>::type
|
||||
f(File& file);
|
||||
@endcode
|
||||
*/
|
||||
#if BEAST_DOXYGEN
|
||||
template<class T>
|
||||
struct is_file : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
template<class T, class = void>
|
||||
struct is_file : std::false_type {};
|
||||
|
||||
template<class T>
|
||||
struct is_file<T, detail::void_t<decltype(
|
||||
std::declval<bool&>() = std::declval<T const&>().is_open(),
|
||||
std::declval<T&>().close(std::declval<error_code&>()),
|
||||
std::declval<T&>().open(
|
||||
std::declval<char const*>(),
|
||||
std::declval<file_mode>(),
|
||||
std::declval<error_code&>()),
|
||||
std::declval<std::uint64_t&>() = std::declval<T&>().size(
|
||||
std::declval<error_code&>()),
|
||||
std::declval<std::uint64_t&>() = std::declval<T&>().pos(
|
||||
std::declval<error_code&>()),
|
||||
std::declval<T&>().seek(
|
||||
std::declval<std::uint64_t>(),
|
||||
std::declval<error_code&>()),
|
||||
std::declval<std::size_t&>() = std::declval<T&>().read(
|
||||
std::declval<void*>(),
|
||||
std::declval<std::size_t>(),
|
||||
std::declval<error_code&>()),
|
||||
std::declval<std::size_t&>() = std::declval<T&>().write(
|
||||
std::declval<void const*>(),
|
||||
std::declval<std::size_t>(),
|
||||
std::declval<error_code&>()),
|
||||
(void)0)>> : std::integral_constant<bool,
|
||||
std::is_default_constructible<T>::value &&
|
||||
std::is_destructible<T>::value
|
||||
> {};
|
||||
#endif
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
|
@ -24,6 +24,9 @@ add_executable (core-tests
|
||||
doc_snippets.cpp
|
||||
drain_buffer.cpp
|
||||
error.cpp
|
||||
file.cpp
|
||||
file_stdio.cpp
|
||||
file_test.hpp
|
||||
flat_buffer.cpp
|
||||
handler_alloc.cpp
|
||||
handler_ptr.cpp
|
||||
|
@ -19,6 +19,8 @@ unit-test core-tests :
|
||||
doc_snippets.cpp
|
||||
drain_buffer.cpp
|
||||
error.cpp
|
||||
file.cpp
|
||||
file_stdio.cpp
|
||||
flat_buffer.cpp
|
||||
handler_alloc.cpp
|
||||
handler_ptr.cpp
|
||||
|
9
test/core/file.cpp
Normal file
9
test/core/file.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <beast/core/file.hpp>
|
31
test/core/file_stdio.cpp
Normal file
31
test/core/file_stdio.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <beast/core/file_stdio.hpp>
|
||||
|
||||
#include "file_test.hpp"
|
||||
|
||||
#include <beast/core/type_traits.hpp>
|
||||
#include <beast/unit_test/suite.hpp>
|
||||
|
||||
namespace beast {
|
||||
|
||||
class file_stdio_test
|
||||
: public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
void
|
||||
run()
|
||||
{
|
||||
doTestFile<file_stdio>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(file_stdio,core,beast);
|
||||
|
||||
} // beast
|
122
test/core/file_test.hpp
Normal file
122
test/core/file_test.hpp
Normal file
@ -0,0 +1,122 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_TEST_CORE_FILE_TEST_HPP
|
||||
#define BEAST_TEST_CORE_FILE_TEST_HPP
|
||||
|
||||
#include <beast/core/type_traits.hpp>
|
||||
#include <beast/unit_test/suite.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
|
||||
template<class File>
|
||||
void
|
||||
doTestFile(beast::unit_test::suite& test)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(is_file<File>::value);
|
||||
|
||||
error_code ec;
|
||||
auto const temp = boost::filesystem::unique_path();
|
||||
|
||||
{
|
||||
{
|
||||
File f1;
|
||||
test.BEAST_EXPECT(! f1.is_open());
|
||||
f1.open(temp.string<std::string>().c_str(), file_mode::write, ec);
|
||||
test.BEAST_EXPECT(! ec);
|
||||
File f2{std::move(f1)};
|
||||
test.BEAST_EXPECT(! f1.is_open());
|
||||
test.BEAST_EXPECT(f2.is_open());
|
||||
File f3;
|
||||
f3 = std::move(f2);
|
||||
test.BEAST_EXPECT(! f2.is_open());
|
||||
test.BEAST_EXPECT(f3.is_open());
|
||||
f1.close(ec);
|
||||
test.BEAST_EXPECT(! ec);
|
||||
auto const temp2 = boost::filesystem::unique_path();
|
||||
f3.open(temp2.string<std::string>().c_str(), file_mode::read, ec);
|
||||
test.BEAST_EXPECT(ec);
|
||||
ec.assign(0, ec.category());
|
||||
}
|
||||
boost::filesystem::remove(temp, ec);
|
||||
test.BEAST_EXPECT(! ec);
|
||||
}
|
||||
|
||||
File f;
|
||||
|
||||
test.BEAST_EXPECT(! f.is_open());
|
||||
|
||||
f.size(ec);
|
||||
test.BEAST_EXPECT(ec == errc::invalid_argument);
|
||||
ec.assign(0, ec.category());
|
||||
|
||||
f.pos(ec);
|
||||
test.BEAST_EXPECT(ec == errc::invalid_argument);
|
||||
ec.assign(0, ec.category());
|
||||
|
||||
f.seek(0, ec);
|
||||
test.BEAST_EXPECT(ec == errc::invalid_argument);
|
||||
ec.assign(0, ec.category());
|
||||
|
||||
f.read(nullptr, 0, ec);
|
||||
test.BEAST_EXPECT(ec == errc::invalid_argument);
|
||||
ec.assign(0, ec.category());
|
||||
|
||||
f.write(nullptr, 0, ec);
|
||||
test.BEAST_EXPECT(ec == errc::invalid_argument);
|
||||
ec.assign(0, ec.category());
|
||||
|
||||
f.open(temp.string<std::string>().c_str(), file_mode::write, ec);
|
||||
test.BEAST_EXPECT(! ec);
|
||||
|
||||
std::string const s = "Hello, world!";
|
||||
f.write(s.data(), s.size(), ec);
|
||||
test.BEAST_EXPECT(! ec);
|
||||
|
||||
auto size = f.size(ec);
|
||||
test.BEAST_EXPECT(! ec);
|
||||
test.BEAST_EXPECT(size == s.size());
|
||||
|
||||
auto pos = f.pos(ec);
|
||||
test.BEAST_EXPECT(! ec);
|
||||
test.BEAST_EXPECT(pos == size);
|
||||
|
||||
f.close(ec);
|
||||
test.BEAST_EXPECT(! ec);
|
||||
|
||||
f.open(temp.string<std::string>().c_str(), file_mode::read, ec);
|
||||
test.BEAST_EXPECT(! ec);
|
||||
|
||||
std::string buf;
|
||||
buf.resize(s.size());
|
||||
f.read(&buf[0], buf.size(), ec);
|
||||
test.BEAST_EXPECT(! ec);
|
||||
test.BEAST_EXPECT(buf == s);
|
||||
|
||||
f.seek(1, ec);
|
||||
test.BEAST_EXPECT(! ec);
|
||||
buf.resize(3);
|
||||
f.read(&buf[0], buf.size(), ec);
|
||||
test.BEAST_EXPECT(! ec);
|
||||
test.BEAST_EXPECT(buf == "ell");
|
||||
|
||||
pos = f.pos(ec);
|
||||
test.BEAST_EXPECT(! ec);
|
||||
test.BEAST_EXPECT(pos == 4);
|
||||
|
||||
f.close(ec);
|
||||
test.BEAST_EXPECT(! ec);
|
||||
boost::filesystem::remove(temp, ec);
|
||||
test.BEAST_EXPECT(! ec);
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
#include <beast/core/error.hpp>
|
||||
#include <beast/core/file_base.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/type_traits.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
@ -244,5 +245,56 @@ struct FieldsReader
|
||||
//]
|
||||
};
|
||||
|
||||
//[concept_File
|
||||
|
||||
struct File
|
||||
{
|
||||
/** Default constructor
|
||||
|
||||
There is no open file initially.
|
||||
*/
|
||||
File();
|
||||
|
||||
/** Destructor
|
||||
|
||||
If the file is open it is first closed.
|
||||
*/
|
||||
~File();
|
||||
|
||||
/// Returns `true` if the file is open
|
||||
bool
|
||||
is_open() const;
|
||||
|
||||
/// Close the file if open
|
||||
void
|
||||
close(error_code& ec);
|
||||
|
||||
/// Open a file at the given path with the specified mode
|
||||
void
|
||||
open(char const* path, file_mode mode, error_code& ec);
|
||||
|
||||
/// Return the size of the open file
|
||||
std::uint64_t
|
||||
size(error_code& ec) const;
|
||||
|
||||
/// Return the current position in the open file
|
||||
std::uint64_t
|
||||
pos(error_code& ec) const;
|
||||
|
||||
/// Adjust the current position in the open file
|
||||
void
|
||||
seek(std::uint64_t offset, error_code& ec);
|
||||
|
||||
/// Read from the open file
|
||||
std::size_t
|
||||
read(void* buffer, std::size_t n, error_code& ec) const;
|
||||
|
||||
/// Write to the open file
|
||||
std::size_t
|
||||
write(void const* buffer, std::size_t n, error_code& ec);
|
||||
};
|
||||
|
||||
//]
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
Reference in New Issue
Block a user