Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
Flamefire committed May 14, 2020
2 parents ac0da0f + e4f82f6 commit 6d8ddd2
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 36 deletions.
33 changes: 33 additions & 0 deletions .github/workflows/update_standalone.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
on:
push:
branches: [develop]

name: Update standalone branch

env:
STANDALONE_BRANCH_NAME: standalone

jobs:
update:
name: Update standalone branch
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup git
run: |
git config --global user.email "[email protected]"
git config --global user.name "$GITHUB_ACTOR"
git fetch
- name: Create standalone version
run: |
bash tools/create_standalone.sh /tmp/nowide_standalone
git checkout "$STANDALONE_BRANCH_NAME" -- || git checkout -b "$STANDALONE_BRANCH_NAME"
git rm -r *
mv /tmp/nowide_standalone/* .
git add .
- name: Commit and push
run: |
git commit -am "Include '${{github.event.head_commit.message}}'"
remote_repo="https://${GITHUB_ACTOR}:${{secrets.GITHUB_TOKEN}}@github.com/${GITHUB_REPOSITORY}.git"
git push "$remote_repo" HEAD:$STANDALONE_BRANCH_NAME
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

cmake_minimum_required(VERSION 3.9)
# Version number starts at 10 to avoid conflicts with Boost version
set(_version 10.0.1)
set(_version 10.0.2)
if(BOOST_SUPERPROJECT_SOURCE_DIR)
set(_version ${BOOST_SUPERPROJECT_VERSION})
endif()
Expand Down
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,26 @@ Distributed under the [Boost Software License, Version 1.0](http://www.boost.org
* C++03 **(will be raised to C++11 by mid 2020)**
* optional C++11/17 support
* Usable outside of Boost via CMake
* Compiled library on every OS

Note on the last point:
Having a compiled library allows cross-platform access to e.g. `setenv` which would not be available when using a `-std=c++nn` flag.
This is different to the version available prior to the inclusion in Boost.

### Requirements (Boost version)

* C++03 (or higher) compatible compiler
* Boost (>= 1.56)
* CMake (when not using as part of Boost) or B2 (otherwise)

### Requirements (Standalone version)

The [standalone branch](https://github.com/boostorg/nowide/tree/standalone) keeps track of the [develop branch](https://github.com/boostorg/nowide/tree/develop) and can be used without any other part of Boost.
It is automatically updated so referring to a specific commit is recommended.
You can also use the standalone source archive which is part of every release.

* C++11 (or higher) compatible compiler
* CMake

# Quickstart

Expand Down
5 changes: 5 additions & 0 deletions doc/changelog.dox
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@

\section changelog Changelog

\subsection changelog_10_0_2 Nowide 10.0.2

- boost::nowide::cin now ignores CR (\r) characters and treats CTRL+Z at the beginning of a line as EOF (matching std::cin behavior)
- boost::nowide::cin supports sync by flushing the input and console buffer

\subsection changelog_10_0_1 Nowide 10.0.1 (Boost 1.73)

- IMPORTANT: C++03 support is deprecated and will be removed in the next Boost release
Expand Down
6 changes: 3 additions & 3 deletions doc/main.dox
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,9 @@ This very simple and straightforward approach helps writing Unicode aware progra
Watch the use of \c boost::nowide::args, \c boost::nowide::ifstream and \c boost::nowide::cerr/cout.
On Non-Windows it does nothing, but on Windows the following happens:

- \c boost::nowide::args uses the Windows API to retrieve UTF-16 arguments, converts them to UTF-8
and replaces the original \c argv (and optionally \c env) to point to those, internally stored
UTF-8 strings.
- \c boost::nowide::args retrieves UTF-16 arguments from the Windows API, converts them to UTF-8,
and temporarily replaces the original \c argv (and optionally \c env) with pointers to those internally stored
UTF-8 strings for the lifetime of the instance.
- \c boost::nowide::ifstream converts the passed filename (which is now valid UTF-8) to UTF-16
and calls the Windows Wide API to open the file stream which can then be used as usual.
- Similarily \c boost::nowide::cerr and \c boost::nowide::cout use an underlying stream buffer
Expand Down
23 changes: 16 additions & 7 deletions include/boost/nowide/args.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,29 @@ namespace nowide {
#else

///
/// \brief args is a class that fixes standard main() function arguments and changes them to UTF-8 under
/// Microsoft Windows.
/// \brief \c args is a class that temporarily replaces standard main() function arguments with their
/// equal, but UTF-8 encoded values under Microsoft Windows for the lifetime of the instance.
///
/// The class uses \c GetCommandLineW(), \c CommandLineToArgvW() and \c GetEnvironmentStringsW()
/// in order to obtain the information. It does not relate to actual values of argc,argv and env
/// under Windows.
/// in order to obtain Unicode-encoded values.
/// It does not relate to actual values of argc, argv and env under Windows.
///
/// It restores the original values in its destructor
/// It restores the original values in its destructor (usually at the end of the \c main function).
///
/// If any of the system calls fails, an exception of type std::runtime_error will be thrown
/// and argc, argv, env remain unchanged.
///
/// \note the class owns the memory of the newly allocated strings
/// \note The class owns the memory of the newly allocated strings.
/// So you need to keep it alive as long as you use the values.
///
/// Usage:
/// \code
/// int main(int argc, char** argv, char** env) {
/// boost::nowide::args _(argc, argv, env); // Note the _ as a "don't care" name for the instance
/// // Use argv and env as usual, they are now UTF-8 encoded on Windows
/// return 0; // Memory held by args is released
/// }
/// \endcode
class args
{
public:
Expand All @@ -69,7 +78,7 @@ namespace nowide {
fix_env(env);
}
///
/// Restore original argc,argv,env values, if changed
/// Restore original argc, argv, env values, if changed
///
~args()
{
Expand Down
72 changes: 48 additions & 24 deletions src/iostream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,20 @@ namespace nowide {
class console_input_buffer : public std::streambuf
{
public:
console_input_buffer(HANDLE h) : handle_(h), wsize_(0)
console_input_buffer(HANDLE h) : handle_(h), wsize_(0), was_newline_(true)
{}

protected:
int sync()
{
if(FlushConsoleInputBuffer(handle_) == 0)
return -1;
wsize_ = 0;
was_newline_ = true;
pback_buffer_.clear();
setg(0, 0, 0);
return 0;
}
int pbackfail(int c)
{
if(c == traits_type::eof())
Expand All @@ -134,27 +144,24 @@ namespace nowide {
return 0;
}

char* pnext;
if(pback_buffer_.empty())
{
pback_buffer_.resize(4);
char* b = &pback_buffer_[0];
char* e = b + pback_buffer_.size();
setg(b, e - 1, e);
*gptr() = traits_type::to_char_type(c);
pnext = &pback_buffer_[0] + pback_buffer_.size() - 1u;
} else
{
size_t n = pback_buffer_.size();
std::vector<char> tmp;
tmp.resize(n * 2);
memcpy(&tmp[n], &pback_buffer_[0], n);
tmp.swap(pback_buffer_);
char* b = &pback_buffer_[0];
char* e = b + n * 2;
char* p = b + n - 1;
*p = traits_type::to_char_type(c);
setg(b, p, e);
pback_buffer_.resize(n * 2);
std::memcpy(&pback_buffer_[n], &pback_buffer_[0], n);
pnext = &pback_buffer_[0] + n - 1;
}

char* pFirst = &pback_buffer_[0];
char* pLast = pFirst + pback_buffer_.size();
setg(pFirst, pnext, pLast);
*gptr() = traits_type::to_char_type(c);

return 0;
}

Expand All @@ -178,27 +185,43 @@ namespace nowide {

size_t read()
{
namespace uf = detail::utf;
DWORD read_wchars = 0;
size_t n = wbuffer_size - wsize_;
const size_t n = wbuffer_size - wsize_;
if(!ReadConsoleW(handle_, wbuffer_ + wsize_, static_cast<DWORD>(n), &read_wchars, 0))
return 0;
wsize_ += read_wchars;
char* out = buffer_;
wchar_t* p = wbuffer_;
wchar_t* e = wbuffer_ + wsize_;
uf::code_point c = 0;
while((c = decoder::decode(p, e)) != uf::incomplete)
const wchar_t* cur_input_ptr = wbuffer_;
const wchar_t* const end_input_ptr = wbuffer_ + wsize_;
while(cur_input_ptr != end_input_ptr)
{
if(c == uf::illegal)
const wchar_t* const prev_input_ptr = cur_input_ptr;
detail::utf::code_point c = decoder::decode(cur_input_ptr, end_input_ptr);
// If incomplete restore to beginning of incomplete char to use on next buffer
if(c == detail::utf::incomplete)
{
cur_input_ptr = prev_input_ptr;
break;
}
if(c == detail::utf::illegal)
c = BOOST_NOWIDE_REPLACEMENT_CHARACTER;
assert(out - buffer_ + encoder::width(c) <= static_cast<int>(buffer_size));
out = encoder::encode(c, out);
wsize_ = e - p;
// Skip \r chars as std::cin does
if(c != '\r')
out = encoder::encode(c, out);
}

wsize_ = end_input_ptr - cur_input_ptr;
if(wsize_ > 0)
std::memmove(wbuffer_, e - wsize_, sizeof(wchar_t) * wsize_);
std::memmove(wbuffer_, end_input_ptr - wsize_, sizeof(wchar_t) * wsize_);

// A CTRL+Z at the start of the line should be treated as EOF
if(was_newline_ && out > buffer_ && buffer_[0] == '\x1a')
{
sync();
return 0;
}
was_newline_ = out == buffer_ || out[-1] == '\n';

return out - buffer_;
}
Expand All @@ -210,6 +233,7 @@ namespace nowide {
HANDLE handle_;
size_t wsize_;
std::vector<char> pback_buffer_;
bool was_newline_;
};

winconsole_ostream::winconsole_ostream(int fd, winconsole_ostream* tieStream) : std::ostream(0)
Expand Down
3 changes: 3 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ boost_nowide_add_test(test_env_win SRC test_env.cpp DEFINITIONS BOOST_NOWIDE_TES
boost_nowide_add_test(test_fstream)
boost_nowide_add_test(test_fstream_cxx11)
boost_nowide_add_test(test_iostream)
if(MSVC AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
set_target_properties(${PROJECT_NAME}-test_iostream PROPERTIES VS_DEBUGGER_COMMAND_ARGUMENTS -i)
endif()
boost_nowide_add_test(test_stackstring)
boost_nowide_add_test(test_stdio)
boost_nowide_add_test(test_system_n SRC test_system.cpp DEFINITIONS BOOST_NOWIDE_TEST_USE_NARROW=1)
Expand Down
19 changes: 19 additions & 0 deletions test/test_iostream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <boost/nowide/iostream.hpp>

#include <boost/nowide/detail/utf.hpp>
#include <limits>
#include <string>

#include "test.hpp"
Expand Down Expand Up @@ -75,6 +76,7 @@ void test_main(int argc, char** argv, char**)
TEST(boost::nowide::cerr);
if(argc == 2 && argv[1] == std::string("-i"))
{
boost::nowide::cout << "Input 2 strings" << std::endl;
std::string v1, v2;
boost::nowide::cin >> v1 >> v2;
TEST(boost::nowide::cin);
Expand All @@ -83,5 +85,22 @@ void test_main(int argc, char** argv, char**)
boost::nowide::cout << "First: " << v1 << std::endl;
boost::nowide::cout << "Second: " << v2 << std::endl;
TEST(boost::nowide::cout);

// Check sync
boost::nowide::cout << "Input 2 strings\n";
boost::nowide::cout.flush();
TEST(boost::nowide::cin >> v1);
boost::nowide::cin.sync();
boost::nowide::cout << "First: " << v1 << std::endl;
boost::nowide::cout << "2nd string should be ignored. Input 1 more + [ENTER]" << std::endl;
// And check getline not getting the CR
TEST(std::getline(boost::nowide::cin, v1));
TEST(!v1.empty() && v1[v1.size() - 1u] != '\r');
boost::nowide::cout << "Value: " << v1 << std::endl;

boost::nowide::cout << "Press ENTER to exit";
boost::nowide::cin.clear();
boost::nowide::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
boost::nowide::cin.get();
}
}
2 changes: 1 addition & 1 deletion tools/create_standalone.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fi
mkdir -p "$targetFolder"/include

cp -r include/boost/nowide "$targetFolder"/include
cp -r src test cmake CMakeLists.txt LICENSE "$targetFolder"
cp -r src test cmake CMakeLists.txt LICENSE README.md "$targetFolder"
cp standalone/*.hpp "$targetFolder"/include/nowide
mv "$targetFolder/cmake/BoostAddOptions.cmake" "$targetFolder/cmake/NowideAddOptions.cmake"
mv "$targetFolder/cmake/BoostAddWarnings.cmake" "$targetFolder/cmake/NowideAddWarnings.cmake"
Expand Down

0 comments on commit 6d8ddd2

Please sign in to comment.