2
0
mirror of https://github.com/boostorg/nowide.git synced 2026-02-22 15:32:35 +00:00

Many updates

This commit is contained in:
Artyom Beilis
2012-05-28 00:35:34 +03:00
parent bdd47e6fc7
commit 0cef64d8e8
22 changed files with 2131 additions and 398 deletions

View File

@@ -1,7 +1,10 @@
cmake_minimum_required(VERSION 2.6)
include_directories(.)
include_directories(/home/artik/Packages/boost/boost_1_49_0)
if(NOT BOOST_PATH)
set(BOOST_PATH ${CMAKE_CURRENT_SOURCE_PATH})
endif()
include_directories(${BOOST_PATH})
enable_testing()
@@ -20,15 +23,11 @@ foreach(TEST ${BOOST_NOWIDE_TESTS})
add_test(${TEST} ${TEST})
endforeach()
if(WIN32)
add_library(boost_nowide SHARED libs/nowide/src/iostream.cpp)
set_target_properties(boost_nowide PROPERTIES COMPILE_DEFINITIONS BOOST_NOWIDE_DYN_LINK)
set_target_properties(test_iostream PROPERTIES COMPILE_DEFINITIONS BOOST_NOWIDE_DYN_LINK)
target_link_libraries(test_iostream boost_nowide)
endif()
add_library(boost_nowide SHARED libs/nowide/src/iostream.cpp)
set_target_properties(boost_nowide PROPERTIES COMPILE_DEFINITIONS BOOST_NOWIDE_DYN_LINK)
set_target_properties(test_iostream PROPERTIES COMPILE_DEFINITIONS BOOST_NOWIDE_DYN_LINK)
target_link_libraries(test_iostream boost_nowide)
add_executable(test_system libs/nowide/test/test_system.cpp)
add_test(test_system_1 test_system "-1")
add_test(test_system_2 test_system "-2")
add_test(test_system_3 test_system "-3")
add_test(test_system_w test_system "-2")
add_test(test_system_n test_system "-n")
add_test(test_system_w test_system "-w")

View File

@@ -17,7 +17,7 @@
namespace boost {
namespace nowide {
#ifndef BOOST_WINDOWS
#if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_DOXYGEN)
class args {
public:
args(int &,char **&) {}
@@ -26,12 +26,25 @@ namespace boost {
#else
///
/// \brief args is a class that fixes standard main() function arguments and changes them to UTF-8 under
/// Microsoft Windows.
///
/// \note the class owns the memory of the newly allocated strings
///
class args {
public:
///
/// Fix command line agruments
///
args(int &argc,char **&argv)
{
fix_args(argc,argv);
}
///
/// Fix command line agruments and environment
///
args(int &argc,char **&argv,char **&en)
{
fix_args(argc,argv);

View File

@@ -13,6 +13,7 @@
#include <stdlib.h>
#include <boost/config.hpp>
#include <boost/nowide/stackstring.hpp>
#include <vector>
#ifdef BOOST_WINDOWS
#include <windows.h>
@@ -20,12 +21,17 @@
namespace boost {
namespace nowide {
#ifndef BOOST_WINDOWS
#if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_DOXYGEN)
using ::getenv;
using ::setenv;
using ::unsetenv;
using ::putenv;
#else
///
/// \brief UTF-8 aware getenv. Returns 0 if the variable is not set.
///
/// This function is not thread safe or reenterable as defined by the standard library
///
inline char *getenv(char const *key)
{
static stackstring value;
@@ -53,6 +59,12 @@ namespace boost {
return 0;
return value.c_str();
}
///
/// \brief UTF-8 aware setenv, \a key - the variable name, \a value is a new UTF-8 value,
///
/// if override is not 0, that the old value is always overridded, otherwise,
/// if the variable exists it remains unchanged
///
inline int setenv(char const *key,char const *value,int override)
{
wshort_stackstring name;
@@ -70,6 +82,9 @@ namespace boost {
return 0;
return -1;
}
///
/// \brief Remove enviroment variable \a key
///
inline int unsetenv(char const *key)
{
wshort_stackstring name;
@@ -79,6 +94,9 @@ namespace boost {
return 0;
return -1;
}
///
/// \brief UTF-8 aware putenv implementation, expects string in format KEY=VALUE
///
inline int putenv(char *string)
{
char const *key = string;

View File

@@ -14,7 +14,7 @@
namespace boost {
namespace nowide {
///
/// Template function that converts a buffer of UTF sequence in range [source_begin,source_end)
/// \brief Template function that converts a buffer of UTF sequence in range [source_begin,source_end)
/// to the output \a buffer of size \a buffer_size.
///
/// In case of success a NUL terminated string returned (buffer), otherwise 0 is returned.
@@ -61,7 +61,7 @@ namespace boost {
return s;
}
}
/// \end
/// \endcond
///
/// Convert NUL terminated UTF source string to NUL terminated \a output string of size at

View File

@@ -1,225 +0,0 @@
//
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
//
// 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 BOOST_NOWIDE_CPPENV_H_INCLUDED
#define BOOST_NOWIDE_CPPENV_H_INCLUDED
#include <string>
#include <stdlib.h>
#include <map>
#include <boost/config.hpp>
#include <boost/nowide/stackstring.hpp>
#include <boost/locale/encoding_errors.hpp>
#include <vector>
#ifdef BOOST_WINDOWS
#include <windows.h>
#include <wchar.h>
#endif
namespace boost {
namespace nowide {
#ifndef BOOST_WINDOWS
inline bool has_enironment(char const *key)
{
return ::getenv(key)!=0;
}
inline bool has_enironment(std::string const &key)
{
return ::getenv(key.c_str())!=0;
}
inline std::string get_environment(char const *key,char const *def="")
{
char const *v=::getenv(key);
if(!v)
return def;
return v;
}
inline std::string get_environment(std::string const &key,std::string const &def=std::string())
{
char const *v=::getenv(key.c_str());
if(!v)
return def;
return v;
}
inline int set_environment(char const *key,char const *value,bool override=true)
{
return ::setenv(key,value,int(override));
}
inline int set_environment(std::string const &key,std::string const &value,bool override=true)
{
return ::setenv(key.c_str(),value.c_str(),int(override));
}
inline int unset_environment(char const *key)
{
return ::unsetenv(key);
}
inline int unset_environment(std::string const &key)
{
return ::unsetenv(key.c_str());
}
inline std::map<std::string,std::string> get_environment_strings()
{
std::map<std::string,std::string> result;
char **e = environ;
if(!e)
return result;
for(;*e;e++) {
char *key = *e;
char *key_end = strchr(key,'=');
if(key_end == 0)
continue;
std::string skey = std::string(key,key_end);
std::string svalue(key_end + 1);
result[skey]=svalue;
}
return result;
}
#else
inline bool has_enironment(char const *key)
{
wshort_stackstring name;
if(!name.convert(key)) {
throw boost::locale::conv::conversion_error();
}
wchar_t unused;
if(GetEnvironmentVariableW(name.c_str(),&unused,1)==0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND)
return false;
return true;
}
inline bool has_enironment(std::string const &key)
{
return has_enironment(key.c_str());
}
/// \cond INTERNAL
namespace details {
inline bool get_environment_value(char const *key,std::string &result)
{
wshort_stackstring name;
if(!name.convert(key)) {
throw boost::locale::conv::conversion_error();
}
for(;;) {
static const size_t buf_size = 64;
wchar_t buf[buf_size];
size_t n = GetEnvironmentVariableW(name.c_str(),buf,buf_size);
if(n == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND)
return false;
if(n >= buf_size) {
std::vector<wchar_t> tmp(n);
n = GetEnvironmentVariableW(name.c_str(),&tmp[0],tmp.size());
// The size may have changed
if(n == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND)
return false;
if(n >= tmp.size())
continue;
std::string v = convert(&tmp[0]);
v.swap(result);
return true;
}
std::string v = convert(buf);
v.swap(result);
return true;
}
}
}
/// \endcond
inline std::string get_environment(std::string const &key,std::string const &def=std::string())
{
std::string result;
if(details::get_environment_value(key.c_str(),result))
return result;
return def;
}
inline std::string get_environment(char const *key,char const *def="")
{
std::string result;
if(details::get_environment_value(key,result))
return result;
return def;
}
inline int set_environment(char const *key,char const *value,bool override=true)
{
wshort_stackstring name;
if(!name.convert(key)) {
throw boost::locale::conv::conversion_error();
}
if(!override) {
wchar_t unused;
if(!(GetEnvironmentVariableW(name.c_str(),&unused,1)==0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND))
return 0;
}
wstackstring wval;
if(!wval.convert(value))
throw boost::locale::conv::conversion_error();
if(SetEnvironmentVariableW(name.c_str(),wval.c_str()))
return 0;
return -1;
}
inline int set_environment(std::string const &key,std::string const &value,bool override=true)
{
return set_environment(key.c_str(),value.c_str(),override);
}
inline int unset_environment(char const *key)
{
wshort_stackstring name;
if(!name.convert(key)) {
throw boost::locale::conv::conversion_error();
}
if(SetEnvironmentVariableW(name.c_str(),0))
return 0;
return -1;
}
inline int unset_environment(std::string const &key)
{
return unset_environment(key.c_str());
}
inline std::map<std::string,std::string> get_environment_strings()
{
std::map<std::string,std::string> result;
wchar_t *wstrings = 0;
try {
wstrings = GetEnvironmentStringsW();
if(!wstrings)
return result;
for(;*wstrings!=0;wstrings += wcslen(wstrings) + 1) {
wchar_t *key_end = wcschr(wstrings,L'=');
if(key_end == 0)
continue;
short_stackstring key;
if(!key.convert(wstrings,key_end))
continue;
stackstring val;
if(!val.convert(key_end+1))
continue;
result[key.c_str()] = val.c_str();
}
}
catch(...) {
if(wstrings) {
FreeEnvironmentStringsW(wstrings);
wstrings = 0;
}
throw;
}
if(wstrings) {
FreeEnvironmentStringsW(wstrings);
wstrings = 0;
}
return result;
}
#endif
} // nowide
} // boost
#endif
///
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4

View File

@@ -13,6 +13,7 @@
#include <boost/config.hpp>
#include <boost/nowide/convert.hpp>
#include <boost/nowide/stackstring.hpp>
#include <errno.h>
#ifdef BOOST_MSVC
# pragma warning(push)
@@ -22,41 +23,69 @@
namespace boost {
namespace nowide {
#ifndef BOOST_WINDOWS
#if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_DOXYGEN)
using std::fopen;
using std::freopen;
using std::remove;
using std::rename;
#else
///
/// \brief Same as freopen but file_name and mode are UTF-8 strings
///
/// In invalid UTF-8 given, NULL is returned and errno is set to EINVAL
///
inline FILE *freopen(char const *file_name,char const *mode,FILE *stream)
{
wstackstring wname;
wshort_stackstring wmode;
if(!wname.convert(file_name) || !wmode.convert(mode))
if(!wname.convert(file_name) || !wmode.convert(mode)) {
errno = EINVAL;
return 0;
}
return _wfreopen(wname.c_str(),wmode.c_str(),stream);
}
///
/// \brief Same as fopen but file_name and mode are UTF-8 strings
///
/// In invalid UTF-8 given, NULL is returned and errno is set to EINVAL
///
inline FILE *fopen(char const *file_name,char const *mode)
{
wstackstring wname;
wshort_stackstring wmode;
if(!wname.convert(file_name) || !wmode.convert(mode))
if(!wname.convert(file_name) || !wmode.convert(mode)) {
errno = EINVAL;
return 0;
}
return _wfopen(wname.c_str(),wmode.c_str());
}
///
/// \brief Same as rename but old_name and new_name are UTF-8 strings
///
/// In invalid UTF-8 given, -1 is returned and errno is set to EINVAL
///
inline int rename(char const *old_name,char const *new_name)
{
wstackstring wold,wnew;
if(!wold.convert(old_name) || !wnew.convert(new_name))
if(!wold.convert(old_name) || !wnew.convert(new_name)) {
errno = EINVAL;
return -1;
}
return _wrename(wold.c_str(),wnew.c_str());
}
///
/// \brief Same as rename but name is UTF-8 string
///
/// In invalid UTF-8 given, -1 is returned and errno is set to EINVAL
///
inline int remove(char const *name)
{
wstackstring wname;
if(!wname.convert(name))
if(!wname.convert(name)) {
errno = EINVAL;
return -1;
}
return _wremove(wname.c_str());
}
#endif

View File

@@ -17,17 +17,32 @@
namespace boost {
namespace nowide {
#if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_FSTREAM_TESTS)
#if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_FSTREAM_TESTS) && !defined(BOOST_NOWIDE_DOXYGEN)
using std::basic_filebuf;
using std::filebuf;
#else // Windows
///
/// \brief This forward declaration defined the basic_filebuf type.
///
/// it is implemented and specialized for CharType = char, it behaves
/// implements std::filebuf over standard C I/O
///
template<typename CharType,typename Traits = std::char_traits<CharType> >
class basic_filebuf;
///
/// \brief This is implementation of std::filebuf
///
/// it is implemented and specialized for CharType = char, it behaves
/// implements std::filebuf over standard C I/O
///
template<>
class basic_filebuf<char> : public std::basic_streambuf<char> {
public:
///
/// Creates new filebuf
///
basic_filebuf() :
buffer_size_(4),
buffer_(0),
@@ -49,10 +64,16 @@ namespace nowide {
delete [] buffer_;
}
///
/// Same as std::filebuf::open but s is UTF-8 string
///
basic_filebuf *open(std::string const &s,std::ios_base::openmode mode)
{
return open(s.c_str(),mode);
}
///
/// Same as std::filebuf::open but s is UTF-8 string
///
basic_filebuf *open(char const *s,std::ios_base::openmode mode)
{
if(file_) {
@@ -76,6 +97,9 @@ namespace nowide {
file_ = f;
return this;
}
///
/// Same as std::filebuf::close()
///
basic_filebuf *close()
{
bool res = sync() == 0;
@@ -86,6 +110,9 @@ namespace nowide {
}
return res ? this : 0;
}
///
/// Same as std::filebuf::is_open()
///
bool is_open() const
{
return file_ != 0;
@@ -166,28 +193,6 @@ namespace nowide {
#else
#endif
int fixg()
{
if(gptr()!=egptr()) {
std::streamsize off = gptr() - egptr();
setg(0,0,0);
if(fseek(file_,off,SEEK_CUR) != 0)
return -1;
}
setg(0,0,0);
return 0;
}
int fixp()
{
if(pptr()!=0) {
int r = sync();
setp(0,0);
return r;
}
return 0;
}
int overflow(int c)
{
#ifdef BOOST_NOWIDE_DEBUG_FILEBUF
@@ -257,16 +262,6 @@ namespace nowide {
return pubseekoff(-1,std::ios::cur);
}
void reset(FILE *f = 0)
{
sync();
if(file_) {
fclose(file_);
file_ = 0;
}
file_ = f;
}
std::streampos seekoff(std::streamoff off,
std::ios_base::seekdir seekdir,
std::ios_base::openmode /*m*/)
@@ -299,6 +294,39 @@ namespace nowide {
return seekoff(std::streamoff(off),std::ios_base::beg,m);
}
private:
int fixg()
{
if(gptr()!=egptr()) {
std::streamsize off = gptr() - egptr();
setg(0,0,0);
if(fseek(file_,off,SEEK_CUR) != 0)
return -1;
}
setg(0,0,0);
return 0;
}
int fixp()
{
if(pptr()!=0) {
int r = sync();
setp(0,0);
return r;
}
return 0;
}
void reset(FILE *f = 0)
{
sync();
if(file_) {
fclose(file_);
file_ = 0;
}
file_ = f;
}
static wchar_t const *get_mode(std::ios_base::openmode mode)
{
//
@@ -354,6 +382,9 @@ namespace nowide {
std::ios::openmode mode_;
};
///
/// \brief Convinience typedef
///
typedef basic_filebuf<char> filebuf;
#endif // windows

View File

@@ -23,7 +23,7 @@ namespace boost {
/// of std namespace (i.e. not on Windows)
///
namespace nowide {
#if !defined BOOST_WINDOWS && !defined BOOST_NOWIDE_FSTREAM_TESTS
#if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_FSTREAM_TESTS) && !defined(BOOST_NOWIDE_DOXYGEN)
using std::basic_ifstream;
using std::basic_ofstream;
@@ -32,11 +32,9 @@ namespace nowide {
using std::ofstream;
using std::fstream;
#endif
#if defined(BOOST_WINDOWS) || defined(BOOST_DOXYGEN_DOCS) || defined(BOOST_NOWIDE_FSTREAM_TESTS)
#else
///
/// Same as std::basic_ifstream<char> but accepts UTF-8 strings under Windows
/// \brief Same as std::basic_ifstream<char> but accepts UTF-8 strings under Windows
///
template<typename CharType,typename Traits = std::char_traits<CharType> >
class basic_ifstream : public std::basic_istream<CharType,Traits>
@@ -99,7 +97,7 @@ namespace nowide {
};
///
/// Same as std::basic_ofstream<char> but accepts UTF-8 strings under Windows
/// \brief Same as std::basic_ofstream<char> but accepts UTF-8 strings under Windows
///
template<typename CharType,typename Traits = std::char_traits<CharType> >
@@ -161,7 +159,7 @@ namespace nowide {
};
///
/// Same as std::basic_fstream<char> but accepts UTF-8 strings under Windows
/// \brief Same as std::basic_fstream<char> but accepts UTF-8 strings under Windows
///
template<typename CharType,typename Traits = std::char_traits<CharType> >
@@ -224,7 +222,7 @@ namespace nowide {
///
/// Same as std::filebuf but accepts UTF-8 strings under Windows
/// \brief Same as std::filebuf but accepts UTF-8 strings under Windows
///
typedef basic_filebuf<char> filebuf;
///

View File

@@ -16,7 +16,7 @@
namespace boost {
namespace nowide {
#ifndef BOOST_WINDOWS
#if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_DOXYGEN)
using std::cout;
using std::cerr;
using std::cin;
@@ -53,10 +53,29 @@ namespace boost {
/// \endcond
///
/// \brief Same as std::cin, but uses UTF-8
///
/// Note, the stream is not synchronized with stdio and not affected by std::ios::sync_with_stdio
///
extern BOOST_NOWIDE_DECL details::winconsole_istream cin;
///
/// \brief Same as std::cout, but uses UTF-8
///
/// Note, the stream is not synchronized with stdio and not affected by std::ios::sync_with_stdio
///
extern BOOST_NOWIDE_DECL details::winconsole_ostream cout;
///
/// \brief Same as std::cerr, but uses UTF-8
///
/// Note, the stream is not synchronized with stdio and not affected by std::ios::sync_with_stdio
///
extern BOOST_NOWIDE_DECL details::winconsole_ostream cerr;
///
/// \brief Same as std::clog, but uses UTF-8
///
/// Note, the stream is not synchronized with stdio and not affected by std::ios::sync_with_stdio
///
extern BOOST_NOWIDE_DECL details::winconsole_ostream clog;
#endif

View File

@@ -128,9 +128,21 @@ private:
output_char *mem_buffer_;
}; //basic_stackstring
///
/// Convinience typedef
///
typedef basic_stackstring<wchar_t,char,256> wstackstring;
///
/// Convinience typedef
///
typedef basic_stackstring<char,wchar_t,256> stackstring;
///
/// Convinience typedef
///
typedef basic_stackstring<wchar_t,char,16> wshort_stackstring;
///
/// Convinience typedef
///
typedef basic_stackstring<char,wchar_t,16> short_stackstring;

View File

@@ -13,12 +13,18 @@
#include <boost/nowide/stackstring.hpp>
namespace boost {
namespace nowide {
#ifndef BOOST_WINDOWS
#if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_DOXYGEN)
using ::system;
#else // Windows
///
/// Same as std::system but cmd is UTF-8.
///
/// If the input is not valid UTF-8, -1 returned and errno set to EINVAL
///
inline int system(char const *cmd)
{
if(!cmd)

View File

@@ -1,51 +0,0 @@
#define _UNICODE
#include <windows.h>
#include <wchar.h>
#include <string.h>
#include <boost/locale/encoding_utf.hpp>
#include <string>
void write(wchar_t const *s)
{
HANDLE h=GetStdHandle(STD_OUTPUT_HANDLE);
DWORD written = 0;
DWORD dummy;
if(GetConsoleMode(h,&dummy)) {
WriteConsoleW(h,s,wcslen(s),&written,0);
}
else {
std::string tmp = boost::locale::conv::utf_to_utf<char>(s);
WriteFile(h,tmp.c_str(),tmp.size(),&written,0);
}
}
int read(wchar_t *buf,size_t n)
{
HANDLE h=GetStdHandle(STD_INPUT_HANDLE);
DWORD read = 0;
DWORD dummy;
if(GetConsoleMode(h,&dummy)) {
ReadConsoleW(h,buf,n-1,&read,0);
buf[read] = 0;
}
else {
char tmp[256];
ReadFile(h,tmp,sizeof(tmp),&read,0);
tmp[read] = 0;
std::wstring wtmp = boost::locale::conv::utf_to_utf<wchar_t>(tmp);
buf[n-1]=0;
wcsncpy(buf,wtmp.c_str(),n-1);
read = wcslen(buf);
}
return read;
}
int main()
{
write(L"שלום ασφγσφγ мир\n");
wchar_t buf[256];
read(buf,256);
write(buf);
return 0;
}

View File

@@ -0,0 +1,26 @@
# Boost System Library Build Jamfile
# (C) Copyright Beman Dawes 2002, 2006, Artyom Beilis 2012
#
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or www.boost.org/LICENSE_1_0.txt)
# See library home page at http://www.boost.org/libs/nowide
project boost/nowide
: source-location ../src
: usage-requirements # pass these requirement to dependents (i.e. users)
<link>shared:<define>BOOST_NOWIDE_DYN_LINK=1
<link>static:<define>BOOST_NOWIDE_STATIC_LINK=1
;
SOURCES = iostream ;
lib boost_nowide
: $(SOURCES).cpp
: <link>shared:<define>BOOST_SYSTEM_DYN_LINK=1
<link>static:<define>BOOST_SYSTEM_STATIC_LINK=1
;
boost-install boost_system ;

1632
libs/nowide/doc/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

11
libs/nowide/doc/gendoc.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/bash
#
# Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
#
# 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)
#
rm -f html/* && doxygen

212
libs/nowide/doc/main.txt Normal file
View File

@@ -0,0 +1,212 @@
//
// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
//
// 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)
//
/*!
\mainpage Boost.Nowide
Table of Contents:
- \ref main
- \ref main_rationale
- \ref main_the_problem
- \ref main_the_solution
- \ref main_wide
- \ref main_reading
- \ref using
- \ref technical
- \ref technical_imple
- \ref technical_cio
\section main What is Boost.Nowide
Boost.Nowide is a library implemented by Artyom Beilis
that make cross platform Unicode aware programming
ieasier.
\subsection main_rationale Rationale
\subsubsection main_the_problem The Problem
Consider a simple application that splits a big file into chunks, such that
they can be sent by e-mail. It requires doing few very simple taks:
- Access command line arguments: <code>int main(int argc,char **argv)</code>
- Open a input file, open several output files: <code>std::fstream::open(char const *,std::ios::openmode m)</code>
- Remove the files in case of fault: <code>std::remove(char const *file)</code>
- Print a progress report into console: <code>std::cout << file_name </code>
Unfortunately it is impossible to implement this simple task in a plain C++
if the file names contain non-ASCII characters
The simple program that uses the API would work on the systems that use UTF-8
internally -- the vast majority of Unix-Line operating systems: Linux, Mac OS X,
Solaris, BSD. But it would fail on files like <code>War and Peace - Война и мир - מלחמה ושלום.zip</code>
under Microsoft Windows because the native Windows Unicode aware API is Wide-API - UTF-16.
This, even a trivial task is very hard to implement in cross platform manner.
\subsubsection main_the_solution The Solution
Boost.Nowide provides a set of standard library functions that are UTF-8 aware and
makes Unicode aware programming easier.
The library provides:
- Easy to use functions for converting UTF-8 to/from UTF-16
- A class to fixing \c argc, \c argc and \c env \c main parameters to use UTF-8
- UTF-8 aware functions
- \c stdio.h functions:
- \c fopen
- \c freopen
- \c remove
- \c rename
- \c stdlib.h functions
- \c system
- \c getenv
- \c setenv
- \c unsetenv
- \c putenv
- \c fstream
- \c filebuf
- \c fstream/ofstream/ifstream
- \c iostream
- \c cout
- \c cerr
- \c clog
- \c cin
\subsubsection main_wide Why Not Narrow and Wide?
Why not to provide both Wide and Narrow implementations so the
developer can choose to use Wide characters on Unix-Like platforms
Several reasons:
- \c wchar_t is not really portable, it can be 2 bytes, 4 bytes or even 1 byte making Unicode aware programming harder
- Standard C and C++ library uses narrow strings for OS interactions. This library follows this general rule. There is
no such thing as <code>fopen(wchar_t const *,wchar_t const *)</code> in the standard library, so it is better
to stick to the standards rather than re-implement Wide API in "Microsoft Windows Style"
\subsubsection main_reading Further Reading
- <a href="http://www.utf8everywhere.org/">www.utf8everywhere.org</a>
- <a href="http://alfps.wordpress.com/2011/11/22/unicode-part-1-windows-console-io-approaches/">Windows console i/o approaches</a>
\section using Using The Library
The library is mostly header only library, only console I/O requires separate compilation under Windows.
As a developer you are expected to to \c boost::nowide functions instead of the function avalible in the
\c std namespace.
For example, Unicode unaware implementation of line counter:
\code
<fstream>
<iostream>
int main(int argc,char **argv)
{
if(argc!=2) {
std::cerr << "Usage: file_name" << std::endl;
return 1;
}
std::ifstream f(argv[2]);
if(!f) {
std::cerr << "Can't open a file " << argv[2] << std::endl;
return 1;
}
int total_lines = 0
while(f) {
if(f.get() == '\n)
total_lines++;
}
f.close();
std::cout << "File " << argv[2] << " has " << total_lines << " lines" << std::endl;
return 0;
}
\endcode
To make this program handle Unicode properly we do the following changes:
\code
<boost/nowide/args.hpp>
<boost/nowide/fstream.hpp>
<boost/nowide/iostream.hpp>
int main(int argc,char **argv)
{
boost::nowide::args a(argc,argv); // Fix arguments - make them UTF-8
if(argc!=2) {
boost::nowide::cerr << "Usage: file_name" << std::endl; // Unicode aware console
return 1;
}
boost::nowide::ifstream f(argv[2]); // argv[2] - is UTF-8
if(!f) {
// the console can display UTF-8
boost::nowide::cerr << "Can't open a file " << argv[2] << std::endl;
return 1;
}
int total_lines = 0
while(f) {
if(f.get() == '\n)
total_lines++;
}
f.close();
// the console can display UTF-8
boost::nowide::cout << "File " << argv[2] << " has " << total_lines << " lines" << std::endl;
return 0;
}
\endcode
This is very simple and straight forward approach helps writing Unicode aware programs.
\section technical Technical Details
\subsection technical_imple Windows vs POSIX
The library provide UTF-8 aware functions for Microsoft Windows in \c boost::nowide namespace that usually lay in \c std:: namespace,
for example \c std::fopen goes to \c boost::nowide::fopen.
Under POSIX platforms the boost::nowide::fopen and all other functions are aliases to standard library functions:
\code
namespace boost {
namespace nowide {
#ifdef BOOST_WINDOWS
inline FILE *fopen(char const *name,char const *mode)
{
...
}
#else
using std::fopen
#endif
} // nowide
} // boost
\endcode
\subsection technical_cio Console I/O
Console I/O implemented as wrapper over ReadConsoleW/WriteConsoleW unless
the stream is not "atty" like a pipe than ReadFile/WriteFile is used.
This approach eliminates a need of manual code page handling. If TrueType
fonts are used the Unicode aware input and output would work.
*/
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 filetype=cpp.doxygen

16
libs/nowide/index.html Normal file
View File

@@ -0,0 +1,16 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Boost.Locale Documentation</title>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<meta http-equiv="refresh" content="0; URL=doc/html/index.html" />
</head>
<body>
Automatic redirection failed, please go to <a href=
"doc/html/index.html">doc/html/index.html</a>
</body>
</html>
<!-- Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) Distributed under the Boost Software License, Version 1.0 -->

View File

@@ -9,12 +9,10 @@
#include <boost/nowide/iostream.hpp>
#include <boost/nowide/convert.hpp>
#include <stdio.h>
#ifndef BOOST_WINDOWS
# error "This code shold be used only under Windows platforms"
#endif
#include <vector>
#ifdef BOOST_WINDOWS
#ifndef NOMINMAX
# define NOMINMAX
#endif
@@ -75,14 +73,16 @@ namespace details {
return -1;
wchar_t *out = wbuffer_;
uf::code_point c;
size_t decoded = 0;
while(p < e && (c = uf::utf_traits<char>::decode(p,e))!=uf::illegal && c!=uf::incomplete) {
out = uf::utf_traits<wchar_t>::encode(c,out);
decoded = p-b;
}
if(c==uf::illegal)
return -1;
if(!WriteConsoleW(handle_,wbuffer_,out - wbuffer_,0,0))
return -1;
return p - b;
return decoded;
}
static const int buffer_size = 1024;
@@ -175,17 +175,18 @@ namespace details {
wchar_t *e = b + wsize_;
wchar_t *p = b;
uf::code_point c;
wsize_ = e-p;
while(p < e && (c = uf::utf_traits<wchar_t>::decode(p,e))!=uf::illegal && c!=uf::incomplete) {
out = uf::utf_traits<char>::encode(c,out);
wsize_ = e-p;
}
if(c==uf::illegal)
return -1;
wsize_ = (e-p);
if(c==uf::incomplete) {
memmove(b,p,sizeof(wchar_t)*wsize_);
memmove(b,e-wsize_,sizeof(wchar_t)*wsize_);
}
return out - buffer_;
@@ -254,5 +255,6 @@ namespace {
} // nowide
} // boost
#endif
///
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4

View File

@@ -0,0 +1,21 @@
# Boost System Library test Jamfile
# Copyright Beman Dawes 2003, 2006, Artyom Beilis 2012
# Distributed under the Boost Software License, Version 1.0.
# See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt
# See library home page at http://www.boost.org/libs/system
project
;
test-suite "nowide"
: [ run test_convert.cpp ]
[ run test_env.cpp ]
[ run test_fstream.cpp ]
[ run test_iostream.cpp : : : <library>/boost/nowide//boost_nowide ]
[ run test_stdio.cpp ]
[ run test_system.cpp : "-w" : : : test_system_w ]
[ run test_system.cpp : "-n" : : : test_system_n ]
;

View File

@@ -6,7 +6,6 @@
// http://www.boost.org/LICENSE_1_0.txt)
//
#include <boost/nowide/cppenv.hpp>
#include <boost/nowide/cenv.hpp>
#include <iostream>
#include "test.hpp"
@@ -18,8 +17,6 @@ int main()
char penv[256] = {0};
strncpy(penv,("BOOST_TEST2=" + example + "x").c_str(),sizeof(penv)-1);
std::cout << "C API" << std::endl;
TEST(boost::nowide::setenv("BOOST_TEST1",example.c_str(),1)==0);
TEST(boost::nowide::getenv("BOOST_TEST1"));
TEST(boost::nowide::getenv("BOOST_TEST1")==example);
@@ -29,28 +26,6 @@ int main()
TEST(boost::nowide::getenv("BOOST_TEST2"));
TEST(boost::nowide::getenv("BOOST_TEST_INVALID")==0);
TEST(boost::nowide::getenv("BOOST_TEST2")==example + "x");
std::cout << "C++ API C Strings" << std::endl;
TEST(boost::nowide::set_environment("BOOST_TEST3",example.c_str(),true)==0);
TEST(boost::nowide::has_enironment("BOOST_TEST3"));
TEST(boost::nowide::get_environment("BOOST_TEST3")==example);
TEST(boost::nowide::set_environment("BOOST_TEST3","xx",false)==0);
TEST(boost::nowide::get_environment("BOOST_TEST3")==example);
TEST(boost::nowide::get_environment("BOOST_TEST_INVALID","inv")==std::string("inv"));
TEST(boost::nowide::get_environment("BOOST_TEST2")==example + "x");
std::cout << "C++ API C++ Strings" << std::endl;
TEST(boost::nowide::set_environment(std::string("BOOST_TEST4"),example,true)==0);
TEST(boost::nowide::has_enironment(std::string("BOOST_TEST4")));
TEST(boost::nowide::get_environment(std::string("BOOST_TEST4"))==example);
TEST(boost::nowide::set_environment(std::string("BOOST_TEST4"),std::string("xx"),false)==0);
TEST(boost::nowide::get_environment(std::string("BOOST_TEST4"))==example);
TEST(boost::nowide::get_environment(std::string("BOOST_TEST2"))==example + "x");
TEST(boost::nowide::get_environment(std::string("BOOST_TEST_INVALID"),std::string("inv"))==std::string("inv"));
std::cout << "Ok" << std::endl;
return 0;

View File

@@ -21,9 +21,17 @@ int main(int argc,char **argv)
TEST(boost::nowide::cin.get() == c);
}
std::string v1,v2;
boost::nowide::cout << "Normal I/O:" << std::endl;
boost::nowide::cout << example << std::endl;
boost::nowide::cerr << example << std::endl;
boost::nowide::cout << "Flushing each character:" << std::endl;
for(char const *s=example;*s;s++) {
boost::nowide::cout << *s << std::flush;
TEST(boost::nowide::cout);
}
TEST(boost::nowide::cout);
TEST(boost::nowide::cerr);
if(argc==2 && argv[1]==std::string("-i")) {

View File

@@ -9,7 +9,6 @@
#include <boost/nowide/system.hpp>
#include <boost/nowide/args.hpp>
#include <boost/nowide/cenv.hpp>
#include <boost/nowide/cppenv.hpp>
#include <iostream>
#include "test.hpp"
@@ -23,30 +22,21 @@ int main(int argc,char **argv,char **env)
TEST(argv[1]==example);
TEST(argv[2] == 0);
TEST(boost::nowide::getenv("BOOST_NOWIDE_TEST"));
TEST(boost::nowide::has_enironment("BOOST_NOWIDE_TEST"));
TEST(boost::nowide::getenv("BOOST_NOWIDE_TEST_NONE") == 0);
TEST(!boost::nowide::has_enironment("BOOST_NOWIDE_TEST_NONE"));
TEST(boost::nowide::getenv("BOOST_NOWIDE_TEST")==example);
TEST(boost::nowide::get_environment("BOOST_NOWIDE_TEST")==example);
TEST(boost::nowide::get_environment("BOOST_NOWIDE_TEST","default")==example);
TEST(boost::nowide::get_environment("BOOST_NOWIDE_TEST_NONE","default")=="default");
std::string sample = "BOOST_NOWIDE_TEST=" + example;
bool found = false;
std::map<std::string,std::string> strs = boost::nowide::get_environment_strings();
size_t total = 0;
for(char **e=env;*e!=0;e++) {
char *key_end = strchr(*e,'=');
TEST(key_end);
std::string key = std::string(*e,key_end);
std::string value = key_end + 1;
TEST(strs.count(key) == 1);
TEST(strs[key]==value);
TEST(getenv(key.c_str()));
TEST(boost::nowide::getenv(key.c_str()) == value);
if(*e == sample)
found = true;
total ++;
}
TEST(found);
TEST(strs.size() == total);
std::cout << "Subprocess ok" << std::endl;
}
else if(argc==2 && argv[1][0]=='-') {
@@ -66,27 +56,18 @@ int main(int argc,char **argv,char **env)
#endif
}
return 0;
case '1':
TEST(boost::nowide::set_environment(std::string("BOOST_NOWIDE_TEST"),example) == 0);
TEST(boost::nowide::set_environment(std::string("BOOST_NOWIDE_TEST_NONE"),example) == 0);
TEST(boost::nowide::unset_environment(std::string("BOOST_NOWIDE_TEST_NONE")) == 0);
break;
case '2':
TEST(boost::nowide::set_environment("BOOST_NOWIDE_TEST",example.c_str()) == 0);
TEST(boost::nowide::set_environment("BOOST_NOWIDE_TEST_NONE",example.c_str()) == 0);
TEST(boost::nowide::unset_environment("BOOST_NOWIDE_TEST_NONE") == 0);
break;
case '3':
case 'n':
TEST(boost::nowide::setenv("BOOST_NOWIDE_TEST",example.c_str(),1) == 0);
TEST(boost::nowide::setenv("BOOST_NOWIDE_TEST_NONE",example.c_str(),1) == 0);
TEST(boost::nowide::unsetenv("BOOST_NOWIDE_TEST_NONE") == 0);
break;
default:
std::cout << "Invalid parameters expected '-1/-2/-3/-w'" << std::endl;
std::cout << "Invalid parameters expected '-n/-w'" << std::endl;
return 1;
}
std::string command = argv[0];
command += " ";
std::string command = "\"";
command += argv[0];
command += "\" ";
command += example;
TEST(boost::nowide::system(command.c_str()) == 0);
std::cout << "Parent ok" << std::endl;