How to set the std::locale with gcc under cygwin? - c++

I'm trying to make a simple program to enumerate the files on my disks, but I'm stuck at the great UTF frontier.
I'm using boost::recursive_directory_iterator to enumerate the files. That's works great, but Windows is set to "french canada" and many files and directories have french characters (likes é, è, ç). These filenames are not displayed correctly on the screen and I'm using wcout. I see a '▒' instead of the acute chars. Even boost::filesystem::ifstream is unable to open these files.
I tried to add "std::locale::global(std::locale(""))", but at first that only thrown an exception. I have found that when LANG is set to "" while executing the program, the previous command does not throw any more, but it only set the "C" locale instead of being the one use by the OS (which I expect to be "fr_CA.UTF-8" or "fr_CA.ISO8859-1"). Any other value for LANG bring the exception back...
What must be done to have a cygwin gcc program usable in an i18n world?
I have write this to test various locale ID:
#include <iomanip>
#include <iostream>
#include <locale>
using namespace std;
void tryLocale(string ID)
{
try{
cout << "Trying " << std::setw(18) << std::left << "\"" + ID + "\" ";
std::locale Loc(ID.c_str());
cout << "OK (" << Loc.name() << ")" << endl;
}catch(...){
cout << "FAIL" << endl;
}
}
const char *Locales[] = { "", "fr", "fr_CA", "fr_CA.UTF-8", "fr_CA.ISO8859-1", "C", 0};
int main()
{
cout << "Classic = " << std::locale::classic().name() << endl << endl;
int i = 0;
do
{ tryLocale(Locales[i]);
} while(Locales[++i]);
return 0;
}
And that gives me this output (without any LANG or LC_ALL):
Classic = C
Trying "" FAIL
Trying "fr" FAIL
Trying "fr_CA" FAIL
Trying "fr_CA.UTF-8" FAIL
Trying "fr_CA.ISO8859-1" FAIL
With LANG set to "", the first "trying" becomes
Trying "" OK (C)
The exception thrown print this:
terminate called after throwing an instance of 'std::runtime_error'
what(): locale::facet::_S_create_c_locale name not valid

Related

error C2312 is thrown for ifstream::failure and ofstream::failure exceptions

I am writing a small application that modifies a text file. It first creates a copy of the file in case something goes wrong.
The following function creates this copy in the same directory. It takes the file's name as an argument and returns true if the copy is successfully created, and false if it fails.
#include <iostream>
#include <filesystem>
#include <fstream>
#include <string>
using std::ifstream;
using std::ofstream;
using std::string;
using std::cerr;
using std::cin;
using std::cout;
using std::endl;
bool backupFile(string FileName) {
cout << "Creating backup for " << FileName << "..." << endl;
try { // for debugging purposes
string NewName = "bkp_" + FileName;
string CurLine;
ifstream FileCopy(FileName);
ofstream FileBackup(NewName);
if (FileCopy.fail()) { // Could specify how file copy failed?
cerr << "Error opening file " << FileName << ".";
return false;
}
while (getline(FileCopy, CurLine)) { // Copy lines to new file
//cout << "Copying " << CurLine << "\" to " << NewName << "." << endl;
FileBackup << CurLine << "\n";
}
cout << "File successfully backed up to " << NewName << endl;
return true;
}
catch (const ifstream::failure& iE) {
cerr << "Exception thrown opening original file: " << iE.what() << endl;
return false;
}
catch (const ofstream::failure& oE) {
cerr << "Exception thrown outputting copy: " << oE.what() << endl;
}
catch (...) {
cerr << "Unknown exception thrown copying file." << endl;
return false;
}
}
I've used a few catch statements to indicate if there is an issue with the input (ifstream::failure), the output (ofstream::failure), or neither.
During compilation, however, the following error appears:
error C2312: 'const std::ios_base::failure &': is caught by 'const std::ios_base::failure &' on line 42
To me, the error implies that both ifstream::failure and ofstream::failure are caught on ifstream::failure, which seems strange. When I remove the catch for ofstream::failure, it runs fine.
Why is this the case?
ifstream::failure and ofstream::failure are both the same type defined in the std::ios_base base class std::ios_base::failure, you can't catch the same type in two separate catch clauses.
Note that neither of your streams will actually throw any exceptions, by default std::fstream doesn't throw any exceptions. You have to turn exceptions on by calling exceptions:
FileCopy.exceptions(f.failbit);
FileBackup.exceptions(f.failbit);
The above will cause an std::ios_base::failure to be thrown when the stream enters the failed state. As you are already checking for FileCopy.fail() you could just expand that checking to cover other failure cases (e.g. check that FileCopy doesn't fail during getline and that FileBackup also doesn't fail) rather than enabling exceptions.

Native C++ node.js module addon WinHttp Detect Auto Proxy Config Url Error return

I am stuck in a tight spot and I need some help with some C++ code. This is my first attempt at doing C++ and it born mostly from necessity at this point.
I am trying (unsuccessfully it feels) to build a native NAN module for Node.JS that will be used by an Electron app on Windows.
I need it to return the WinHttpDetectAutoProxyConfigUrl when the users Proxy configuration is set to Auto Detect.
I have built this exact thing in C# for another application and it works seamlessly in our distributed user BYOD environment. However in this case I do not wish to be dependent on the dot.net framework unnecessarily.
Right know I am at the extent of my knowledge when it comes to C++ as most of my knowledge over the years has thus far been theoretical. I am hoping that someone that actually works in C++ daily can look at my code and help correct the error that is happening.
I have been trying to debug using the “std::cout” in VSCode.
As you can see from the output at the bottom of the image, that some of it appears to be working and the code is dropping into the “Get Auto URL” IF block as expected. However the output is very iritic (“�����”) and nothing like the wpad.dat URL I was expecting to see returned from the wpad protocol implemented by the winhttp.dll.
My Problem:
It is as though the result is blank and then the “char buffer[2083];” is being sent to the stdOut and the characters are all encoded wrong.
Any help on this would be very helpful so thanks in advance.
Please see the code below.
main.cpp
#include <nan.h>
#include <Windows.h>
#include <Winhttp.h>
#include <iostream>
#pragma comment(lib, "winhttp.lib")
using namespace std;
// NAN_METHOD is a Nan macro enabling convenient way of creating native node functions.
// It takes a method's name as a param. By C++ convention, I used the Capital cased name.
NAN_METHOD(AutoProxyConfigUrl) {
cout << "AutoProxyConfigUrl" << "\n";
v8::Isolate* isolate = info.GetIsolate(); // args.GetIsolate();
LPWSTR strConfigUrl = NULL;
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG MyProxyConfig;
if(!WinHttpGetIEProxyConfigForCurrentUser(&MyProxyConfig))
{
//check the error DWORD Err = GetLastError();
DWORD Err = GetLastError();
cout << "WinHttpGetIEProxyConfigForCurrentUser failed with the following error number: " << Err << "\n";
switch (Err)
{
case ERROR_FILE_NOT_FOUND:
cout << "The error is ERROR_FILE_NOT_FOUND" << "\n";
break;
case ERROR_WINHTTP_INTERNAL_ERROR:
cout << "ERROR_WINHTTP_INTERNAL_ERROR" << "\n";
break;
case ERROR_NOT_ENOUGH_MEMORY:
cout << "ERROR_NOT_ENOUGH_MEMORY" << "\n";
break;
default:
cout << "Look up error in header file." << "\n";
break;
}//end switch
//TODO this might not be a good idea but it is worth trying
strConfigUrl = L"http://wpad/wpad.dat"; //Default to Fallback wpad
}//end if
else
{
//no error so check the proxy settings and free any strings
cout << "Auto Detect is: " << MyProxyConfig.fAutoDetect << "\n";
if(MyProxyConfig.fAutoDetect){
cout << "Get Auto URL" << "\n";
if (!WinHttpDetectAutoProxyConfigUrl(WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A, &strConfigUrl))
{
cout << "Error getting URL" << "\n";
//This error message is not necessarily a problem and can be ignored if you are using direct connection. you get this error if you are having direct connection.
//check the error DWORD Err = GetLastError();
DWORD Err = GetLastError();
if (ERROR_WINHTTP_AUTODETECTION_FAILED == Err)
{
strConfigUrl = L"http://wpad/wpad.dat"; //Default to Fallback wpad
}
//TODO work out what to do with the other errors
}
}
if(NULL != MyProxyConfig.lpszAutoConfigUrl)
{
wcout << "AutoConfigURL (MyProxyConfig.lpszAutoConfigUrl) is: " << MyProxyConfig.lpszAutoConfigUrl << "\n";
GlobalFree(MyProxyConfig.lpszAutoConfigUrl);
}
if(NULL != MyProxyConfig.lpszProxy)
{
wcout << "AutoConfigURL (MyProxyConfig.lpszProxy) is: " << MyProxyConfig.lpszProxy << "\n";
GlobalFree(MyProxyConfig.lpszProxy);
}
if(NULL != MyProxyConfig.lpszProxyBypass)
{
wcout << "AutoConfigURL is: " << MyProxyConfig.lpszProxyBypass << "\n";
GlobalFree(MyProxyConfig.lpszProxyBypass);
}
}//end else
//cout << "strConfigUrl" << strConfigUrl << "\n";
char buffer[2083];
wcstombs( buffer, strConfigUrl, wcslen(strConfigUrl) ); // Need wcslen to compute the length of the string
// convert it to string
std::string returnUrl(buffer);
// Create an instance of V8's String type
auto message = Nan::New(returnUrl).ToLocalChecked();
// 'info' is a macro's "implicit" parameter - it's a bridge object between C++ and JavaScript runtimes
// You would use info to both extract the parameters passed to a function as well as set the return value.
info.GetReturnValue().Set(message);
if(strConfigUrl)
GlobalFree(strConfigUrl);
}
// Module initialization logic
NAN_MODULE_INIT(Initialize) {
// Export the `Hello` function (equivalent to `export function Hello (...)` in JS)
NAN_EXPORT(target, AutoProxyConfigUrl);
}
// Create the module called "addon" and initialize it with `Initialize` function (created with NAN_MODULE_INIT macro)
NODE_MODULE(proxyautodetect, Initialize);
main.js
// note that the compiled addon is placed under following path
//const {AutoProxyConfigUrl} = require('./build/Release/proxyautodetect.node');
const {AutoProxyConfigUrl} = require('./build/Debug/proxyautodetect.node');
// `Hello` function returns a string, so we have to console.log it!
console.log(AutoProxyConfigUrl());
Build and Run output:
C:\Code\Work\wpad-auto-detect>if not defined npm_config_node_gyp (node "C:\Program Files\nodejs\node_modules\npm\node_modules\npm-lifecycle\node-gyp-bin\\..\..\node_modules\node-gyp\bin\node-gyp.js" rebuild --debug ) else (node "C:\Program Files\nodejs\node_modules\npm\node_modules\node-gyp\bin\node-gyp.js" rebuild --debug )
Building the projects in this solution one at a time. To enable parallel build, please add the "/m" switch.
main.cpp
win_delay_load_hook.cc
Creating library C:\Code\Work\wpad-auto-detect\build\Debug\proxyautodetect.lib and object C:\Code\Work\wpad-auto-detect\build\Debug\proxyautodet
ect.exp
proxyautodetect.vcxproj -> C:\Code\Work\wpad-auto-detect\build\Debug\\proxyautodetect.node
PS C:\Code\Work\wpad-auto-detect> npm start
> proxyautodetect#1.0.0 start C:\Code\Work\wpad-auto-detect
> node main.js
AutoProxyConfigUrl
Auto Detect is: 1
Get Auto URL
"
"��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������1��J╗
PS C:\Code\Work\wpad-auto-detect>
Image of code output
I did a sort of Trim
int urlLen = wcslen(strConfigUrl) ;
#if DEBUG
cout << "strConfigUrl wcslen : " << urlLen << "\n";
#endif
char buffer[2083]; //This is the max length a URL can be in IE
wcstombs( buffer, strConfigUrl, wcslen(strConfigUrl) ); // Need wcslen to compute the length of the string
// convert it to string
std::string returnUrl(buffer);
// Create an instance of V8's String type and Return only the Length needed so kind of Trim the extra char
auto message = Nan::New(returnUrl.substr(0, urlLen)).ToLocalChecked();

C++ date library fails with timezone

This used to play once. I am trying to get some data from the C++ date library but an exception is caught. I am compiling with
-DUSE_AUTOLOAD=0 -DHAS_REMOTE_API=0 -DUSE_OS_TZDB=1
what is wrong with the code?
#include <iostream>
#include "date/tz.h"
#include <exception>
using namespace date;
using namespace std::chrono;
int main(int argc, char** argv) {
try {
auto current_time_zone = make_zoned("Europe/Athens", std::chrono::system_clock::now());
auto current_day = date::format("%A", current_time_zone);
auto current_time = date::format("%H:%M", current_time_zone);
std::cout << "day: " << current_day << ", time: " << current_time << " in timezone: " << current_time_zone << std::endl;
//std::cout << " in timezone: " << current_time_zone << std::endl;
} catch ( std::exception& e) {
std::cout << e.what() << std::endl;
}
}
You need to use the -pthread flag. tz.cpp uses call_once to do part of the initialisation. And without -pthread it's not going to work (as underneath it need something like __gthread_once). See this for more details.
You can verify if that's the problem by running your example with gdb (use the catch throw).
I'm not positive what the problem is, but I can tell you that this library does not throw an exception that contains the message "Unknown error".
Try adding -DONLY_C_LOCALE=1 to your build flags. This will avoid your std::lib's time_put facet, but will limit you to only the "C" locale. If this fixes the problem, then it is your std::lib's std::time_put facet that threw the exception.

How do I get PCRE to work correctly with Code::blocks?

I am facing some problems while working with PCRE in Code::blocks. I have downloaded PCRE from here. And did all the steps mentioned here. However I am getting a pcr3.dll missing error during execution.
The program can't start because pcre3.dll is missing from your
computer. Try reinstalling the program to fix this problem.
My code:
#include <iostream>
#include <regex.h>
using namespace std;
int main(){
regex_t reg;
string pattern = "[^tpr]{2,}";
string str = "topcoder";
regmatch_t matches[1];
regcomp(&reg,pattern.c_str(),REG_EXTENDED|REG_ICASE);
if (regexec(&reg,str.c_str(),1,matches,0)==0) {
cout << "Match " ;
cout << str.substr(matches[0].rm_so,matches[0].rm_eo-matches[0].rm_so) ;
cout << " found starting at: " ;
cout << matches[0].rm_so ;
cout << " and ending at " ;
cout << matches[0].rm_eo ;
cout << endl;
} else {
cout << "Match not found.";
cout << endl;
}
regfree(&reg);
return 0;
}
I am not sure how to fix this, any ideas?
PS: Above mentioned code is taken from this tutorial.
Copy the DLL to the same directory as the executable that you are running. If that works, you didn't install the DLL correctly or at least not in a way that it can be found by the programs in general. Check out the documentation of the DLL Search Order to get an idea how else you can make the system find the DLL. In particular, you need to know that there is a linker and a loader (aka dynamic/runtime linker/loader), but only one of them is configured inside CodeBlocks!

Why doesn't my function produce output

I'm doing a C++ assingment for a class and I haven't used C++ in a decade so this might be something I'm missing that is simple; however ,I can't seem to figure it out.
I have a class I defined with a function that is producing no output; it looks like it's not even running and I don't have a clue why. Could someone point out my problem to me?
Issue: cout from the function getwords of the class readwords doesn't display any results.
Here is my class:
class readwords {
private:
char c;
//string aword;
public:
void getwords(std::istream& file) {
cout << "I got here" << std::flush;
/*while(file.good()) {
cout << "I got here\n";
c = file.get();
if(isspace(c)) cout << "\n"; //continue;
if(isalnum(c)) {
cout << c; //aword.insert(aword.end(),c);
}
}
*/
}
};
Which is being called from my main:
#include <fstream>
#include <stdlib.h>
#include "lab1.h"
using namespace std;
readwords wordsinfile;
words wordslist;
int main ( int argc, char *argv[] )
{
if ( argc != 2 ) {
// Looks like we have no arguments and need do something about it
// Lets tell the user
cout << "Usage: " << argv[0] <<" <filename>\n";
} else {
// Yeah we have arguements so lets make sure the file exists and it is readable
ifstream ourfile(argv[1]);
if (!ourfile.is_open()) {
// Then we have a problem opening the file
// Lets tell the user and exit
cout << "Error: " << argv[0] << " could not open the file. Exiting\n";
exit (1);
}
// Do we have a ASCII file?
if (isasciifile(ourfile)) {
cout << "Error: " << argv[0] << " only can handle ASCII or non empty files. Exiting\n";
exit(1);
}
// Let ensure we are at the start of the file
ourfile.seekg (0, ios::beg);
// Now lets close it up
ourfile.close();
}
// Ok looks like we have past our tests
// Time to go to work on the file
ifstream ourfile2(argv[1]);
wordsinfile.getwords(ourfile2);
}
Thank you for any help you can provide.
Try to use a debugger. Most IDEs (NetBeans, Code::Blocks, etc) provide an interactive interface with gdb.
I just compiled and ran your code, but nothing wrong with the code itself,
except that I needed to include to use the 'cout' method.
"I got here" has been successfully displayed in my ubuntu machine.
What is your execution environment? You should check it first.
The problem appears to be redefining my own class. When actually coding the function I needed to use:
in readwords::countwords(std::istream& file) {
....
}
Once doing this output produced fine.