C++ how to properly get locale from icu using boost? - c++

I'm trying to get ru locale on OS without one.
I try to get it from icu using boost::locale::generator. Test program is simple I get locale (success) and then I check if russian letter is alphabetical character (fails). What am I doing wrong?
Here is the code:
#include <iostream>
#include <boost/locale.hpp>
#include <boost/locale/localization_backend.hpp>
using namespace std;
int main()
{
using namespace boost::locale;
localization_backend_manager my = localization_backend_manager::global();
my.select("icu");
boost::locale::generator gen(my);
std::locale loc( gen.generate( "ru_RU.UTF-8" ) );
if( !std::isalpha( L'ф', loc ) )
std::cout<< "Oops\n";
else
std::cout << "Ok\n";
return 0;
}
UPD:
Strangely, to_upper, to_lower, to_tiltle and fold_case works ok. Problem is only with is_alpha
UPD2:
Further research showed, that function that use global locale work ok, but functions that take locale as a param fail.
boost::locale::to_upper( str ) works fine, but boost::to_upper_copy( str, loc ) fails.

Related

Qt utf-16 output shows question marks in Windows cmd and powershell -- with minimum reproducible example in C++

Previously, I have asked Qt translations in C++ project are rendered as question marks in cmd and powershell question. The point of the question was that the help message of .\app -h, translated to Cyrillic, is rendered as ?????????.
Since then, I discovered that in https://github.com/RSATom/Qt/blob/master/qtbase/src/corelib/tools/qcommandlineparser.cpp, the Qt messages are printed with qInfo("%ls", qUtf16Printable(message)) on Windows.
In cmd.exe or poweshell.exe I get question marks ?????????, when trying to output a Cyrillic message this way.
I tried to change the font of cmd.exe and powershell.exe to Lucida Console and to execute chcp 10000 (as proposed here UTF-16 on cmd.exe), but this does not help.
Here is the minimum reproducible example:
// > cl main.cpp /I C:\Qt\5.12.12\msvc2017_64\include
// > link main.obj /LIBPATH C:\Qt\5.12.12\msvc2017_64\lib\Qt5Core.lib
#include "QtCore/QtGlobal"
#include "QtCore/QString"
int main()
{
qInfo("%ls", qUtf16Printable("Привет"));
return 0;
}
// > main.exe
// ??????
I would really appreciate any help. There are two problems here. The first: how can I use QCommandLineParser under Windows. The second: if QCommandLineParser (using qInfo("%ls", qUtf16Printable(message))) is okay and not a bug, then how can I make cmd show it all right.
I don't pretend on the answer, but on Windows for Unicode console output you should do something similar to:
#include <QDebug>
#include <iostream>
#include <string>
#include <fcntl.h>
#include <io.h>
#include <stdio.h>
void myMessageOutput( QtMsgType type, const QMessageLogContext & context, const QString & msg )
{
Q_UNUSED( context );
std::wcout << msg.toStdWString() << std::endl;
if( type == QtFatalMsg )
abort();
}
int main()
{
_setmode( _fileno( stdout ), _O_U16TEXT );
qInstallMessageHandler( myMessageOutput );
const std::wstring rs = L"Привет";
const auto s = QString::fromStdWString( rs );
std::wcout << s.toStdWString() << std::endl;
qDebug() << s;
qInfo() << s;
return 0;
}
Accidentally I found the solution. You should create following manifest file for your executable:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<application>
<windowsSettings>
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
</windowsSettings>
</application>
</assembly>
Let it will be named as app.manifest. In CMake project just add app.manifest into sources of your executable.
In the main() function add two lines of code:
#include <Windows.h>
int main( int argc, char ** argv )
{
SetConsoleCP( GetACP() );
SetConsoleOutputCP( GetACP() );
}
And voila...
Printing should be done using UTF-8, so:
// 1 - works.
QTextStream s( stdout );
s << QString( "Вот оно!!!\n" ) << Qt::flush;
// 2 - works.
fputs( qPrintable( QString( "Опа-на...\n" ) ), stdout );
// 3 - works.
std::cout << u8"std::cout работает!!!\n";
// 4 - DOES NOT work.
std::wcout << L"wcout НЕ работает!!!\n";

I invoke LSCopyApplicationURLsForURL() using C++, but get a segment fault

I want to write a C++ program to get associated applications which are suitable to open specified file. I find the LSCopyApplicationURLsForURL API, and create a command line C++ application by XCode.
But after running this program, I always get segment fault. XCode shows EXEC_BAD_ACCESS(code=1, address....) error.
I also tryied running it from sudo, but the same result. What is the problem?
The code:
#include <iostream>
#include <objc/objc.h>
#include <objc/objc-runtime.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
using namespace std;
int main(int argc, const char * argv[]) {
auto url = CFURLRef("file:///Users/efan/src/a.cpp");
auto ret = LSCopyApplicationURLsForURL(url, kLSRolesAll);
cout << ret << endl;
return 0;
}
Try creating your CFURLRef using one of the proper CFURLCreate* methods. See "Creating a CFURL" here.
For example:
auto tempStringURL = CFStringCreateWithCString(nullptr, "/Users/efan/src/a.cpp", kCFStringEncodingUTF8);
auto url = CFURLCreateWithFileSystemPath(nullptr, tempStringURL, kCFURLPOSIXPathStyle, FALSE);
auto ret = LSCopyApplicationURLsForURL(url, kLSRolesAll);
You need to Release the "Created" variables to clean up memory.

Poco DateTimeFormatter - Print timestamp with current timezone

How do I print a Poco::Timestamp with Poco::DateTimeFormatter into a formatted date-time based on the current timezone?
I have a print_pretty_datetime(const Poco::Timestamp &now) where I'll receive a Poco::Timestamp so I can't use a Poco::LocalDateTime unfortunately.
MCVE:
#include "Poco/Timestamp.h"
#include "Poco/Timezone.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include <iostream>
#include <string>
// Cannot change the method signature. I will receive a Poco::Timestamp object
std::string print_pretty_datetime(const Poco::Timestamp &now)
{
return Poco::DateTimeFormatter::format(
now,
Poco::DateTimeFormat::SORTABLE_FORMAT,
Poco::Timezone::tzd()
);
}
int main()
{
Poco::Timestamp now;
std::string dt_now = print_pretty_datetime(now);
std::cout << dt_now << '\n';
return 0;
}
E.g: the string returned is 2019-01-07 11:10:12 (thus UTC+0) whereas my device is in in UTC+1.
In fact, the command date returns Mon Jan 7 12.10.12 CET 2019.
What is the correct parameter for tzd in Poco::DateTimeFormatter::format for printing the date-time based on current locale?
System info:
SMP Debian 4.9.130-2 (2018-10-27) x86_64 GNU/Linux
g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Poco 1.9.0
Get local time by Poco::LocalDateTime, then read its timestemp and pass it into formatter:
Poco::LocalDateTime dateTime;
Poco::Timestamp now = dateTime.timestamp();
You need to define your own string format which includes information about time-zone, because SORTABLE_FORMAT doesn't handle it.
Hint (you can open source of DateTimeFormatter and see how timeZoneDifferential is processed in append function - this parameter doesn't affect hours in output).
So if you change to:
std::string dt_now = Poco::DateTimeFormatter::format(
now,
"%H:%M:%S %z,%Z",
Poco::Timezone::tzd()
);
you will see HH::MM::SS +01:00,+0100 in output.
You can create a Poco::LocalDateTime in the system's current timezone from a Poco::Timestamp via an intermediate Poco::DateTime object.
#include "Poco/LocalDateTime.h"
#include "Poco/DateTime.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/DateTimeFormatter.h"
#include <iostream>
int main(int argc, char** argv)
{
Poco::Timestamp ts;
Poco::DateTime dt(ts);
Poco::LocalDateTime ldt(dt);
std::string str = Poco::DateTimeFormatter::format(ldt, Poco::DateTimeFormat::SORTABLE_FORMAT);
std::cout << str << std::endl;
return 0;
}
Alright, if you don't necessarily need to use a Poco::Timestamp, a solution can be simply to use a Poco::LocalDateTime:
#include "Poco/LocalDateTime.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include <iostream>
#include <string>
int main()
{
Poco::LocalDateTime now;
std::string dt_now = Poco::DateTimeFormatter::format(
now,
Poco::DateTimeFormat::SORTABLE_FORMAT
);
std::cout << dt_now << '\n';
return 0;
}
and this will print the date based on the current timezone.
I still have to use the Poco::Timestamp though as I'll get it as parameter to my print_pretty_datetime(const pc::Timestamp &now), so this answer does not yet applies to my case.

Making directory with vitual studio 2012 coding in c++

Good evening everyone, please I'm writing a Library management application in c++ using virtual studio 2012. I had already writing some codes using Dev c++ it worked but when I switched to visual studio it gives error. It involves creating folders and checking if the folders were actually created. That is using dir and mkdir.
Windows and Linux (POSIX) don't support the same API for most file system functions. You can use Microsoft's platform-specific APIs like CreateDirectory() or use the POSIX-like versions like _mkdir().
If you have a more recent C++ compiler / standard library, you can use the experimental filesystem library that is slated to become part of standard C++, perhaps as early as C++17. If not, you can use Boost.Filesystem from which the pre-standard experimental library was drawn.
Here's a complete, minimal example using Boost.Filesystem, which will work on both Windows and Linux without modification:
#include <iostream>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
int main()
{
if( !fs::exists( "my_dir" ) )
{
if( fs::create_directory( "my_dir" ) )
{
std::cout << "Directory created!\n";
}
}
}
See it run: Coliru.
Here's the same code but with std::experimental::filesystem: Coliru.
You would need the appropriate include and linker paths setup in your build system for either of these to work locally. The biggest "gotcha" using the filesystem is that it throws exceptions for a lot of errors by default. You can either setup try/catch blocks at the appropriate places or pass in an error code param to make it return the status there instead.
#include <stdio.h>
#include <windows.h>
int main() {
if (!CreateDirectoryA("C:\\ABC123", NULL))
{
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
printf("Already Exists");
}else if (GetLastError()== ERROR_PATH_NOT_FOUND)
{
printf("Path not found");
}
}else{
printf("Created..");
}
}
simple function will do.
Thanks alot guys but I found this that solved my problem
#include <iostream>
#include <direct.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
void main( void )
{
if( _mkdir( "\\testtmp" ) == 0 )
{
printf( "Directory '\\testtmp' was successfully created\n" );
system( "dir \\testtmp" );
if( _rmdir( "\\testtmp" ) == 0 )
printf( "Directory '\\testtmp' was successfully removed\n" );
else
printf( "Problem removing directory '\\testtmp'\n" );
}
else
printf( "Problem creating directory '\\testtmp'\n" );
int a;
cin >> a;
}
the cin >> a; is just to keep the output screen so I can see the result

How to run commandline/terminal utils with Boost.Process 0.5?

I foud out there is a new Boost.Process 0.5 but I cant see how to execute across Windows Linux and Mac ping or echo.
I got it working at leaast on Windows with simple:
#include <string>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/process.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/system/error_code.hpp>
namespace bp = boost::process;
namespace bpi = boost::process::initializers;
namespace bio = boost::iostreams;
int main()
{
bp::pipe p = bp::create_pipe();
{
bio::file_descriptor_sink sink(p.sink, bio::close_handle);
boost::filesystem::path p("C:/Windows/System32/cmd.exe");
boost::system::error_code ec;
bp::execute(
bpi::run_exe(p),
bpi::set_cmd_line(L"cmd /c echo --echo-stderr hello"),
bpi::bind_stdout(sink),
bpi::set_on_error(ec)
);
}
bio::file_descriptor_source source(p.source, bio::close_handle);
bio::stream<bio::file_descriptor_source> is(source);
std::string s;
is >> s;
std::cout << s << std::endl;
std::cin.get();
return 0;
}
On windows this works correctly but how to make it crossplatform to work also on Mac and Linux? (I am stupid and do not know how to write one path that would work for any Unix terminal (or at least for Linux Bash and mac default one)) So How to run commandline/terminal utils with Boost.Process 0.5 on Windows and Unix like OSs (better not writing path to terminal each time but just writting app like echo or ping and its arguments)?
...Found related code inside prevoius version:
std::string exe;
std::vector<std::string> args;
#if defined(BOOST_POSIX_API)
exe = "/bin/sh";
args.push_back("sh");
args.push_back("-c");
args.push_back(command);
#elif defined(BOOST_WINDOWS_API)
char sysdir[MAX_PATH];
UINT size = ::GetSystemDirectoryA(sysdir, sizeof(sysdir));
if (!size)
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_shell: GetWindowsDirectory failed"));
BOOST_ASSERT(size < MAX_PATH);
exe = std::string(sysdir) + (sysdir[size - 1] != '\\' ? "\\cmd.exe" : "cmd.exe");
args.push_back("cmd");
args.push_back("/c");
args.push_back(command);
#endif
Under boost.process 0.5 the shell_path() API was introduced so might the following will hook you up
#if defined(BOOST_POSIX_API)
#define SHELL_COMMAND_PREFIX "-c"
#elif defined(BOOST_WINDOWS_API)
#define SHELL_COMMAND_PREFIX "/c"
#endif
filesystem::path shellPath = process::shell_path();
std::string cl = shell_path().string() + " " SHELL_COMMAND_PREFIX " ";
cl += "ping 127.0.0.1";
execute(
set_cmd_line(cl),
throw_on_error()
);
If you really want to hide the #ifdef, I'd go on and edit the boost sources to return also the relevant command prefix (adding new API) , open source after all isn't it ? :).
You could find the relevant sources to edit at boost/process/windows/shell_path.hpp and boost/process/posix/shell_path.hpp