strtok_s was not declared in this scope - c++

I am trying to split my actual key on dot and then extract all the fields after splitting it on dot.
My key would look like something this -
t26.example.1136580077.colox
Below is the code I have which I was in the impression, it should work fine. But somehow whenever I am compiling this code, I always get -
error: âstrtok_sâ was not declared in this scope
Below is my code
if(key) {
vector<string> res;
char* p;
char* totken = strtok_s(key, ".", &p);
while(totken != NULL)
{
res.push_back(totken);
totken = strtok_s(NULL, ".", &p);
}
string field1 = res[0]; // this should be t26
string field2 = res[1]; // this should be example
uint64_t field3 = atoi(res[2].c_str()); // this should be 1136580077
string field4 = res[3]; // this should be colox
cout<<field1<<" "<<field2<<" "<<field3<<" "<<field4<<endl;
}
I am running Ubuntu 12.04 and g++ version is -
g++ (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3
Any idea what wrong I am doing? And if there is any better way of doing it as well, then I am open to that suggestion as well. I am in the impression that using strtok_s will be more efficient and thread safe as well.

#ifndef _MSC_VER
inline
char* strtok_s(char* s, const char* delim, char** context)
{
return strtok_r(s, delim, context);
}
#endif

Related

Convert std::string to STRSAFE_LPCWSTR in an utility method

I'm relatively new to C++ and I'm trying out Windows Notification using Win32 API.
This is the method I have:
BOOL Notification::ShowNotification(std::string title, std::string info) {
NOTIFYICONDATA nid = {
sizeof(nid)
};
nid.uFlags = NIF_INFO | NIF_GUID;
nid.guidItem = __uuidof(AppIcon);
nid.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON;
std::wstring wtitle = std::wstring(title.begin(), title.end());
const wchar_t * wchar_title = (STRSAFE_LPCWSTR) wtitle.c_str();
StringCchCopy(nid.szInfoTitle, sizeof(nid.szInfoTitle), wchar_title);
std::wstring wInfo = std::wstring(info.begin(), info.end());
const wchar_t * wchar_Info = (STRSAFE_LPCWSTR) wInfo.c_str();
StringCchCopy(nid.szInfo, sizeof(nid.szInfo), wchar_Info);
LoadIconMetric(g_hInst, MAKEINTRESOURCE(IDI_NOTIFICATIONICON), LIM_LARGE, & nid.hBalloonIcon);
return Shell_NotifyIcon(NIM_MODIFY, & nid);
}
As you can see, there is duplicate code for converting the string type to STRSAFE_LPCWSTR for the variables title and info. I was thinking of a small utility method that would replace the duplicate code.
Something like this:
void Notification::ConvertToLPCWSTR(std::string input, STRSAFE_LPCWSTR &result)
{
std::wstring wide_string = std::wstring(input.begin(), input.end());
result = (STRSAFE_LPCWSTR)wide_string.c_str();
}
And then use it from the ShowNotification method like this, where wchar_title is passed by reference:
STRSAFE_LPCWSTR wchar_title;
ConvertToLPCWSTR(title, wchar_title);
But it is failing because wide_string variable is stack allocated and it goes out of scope when ConvertToLPCWSTR execution is finished, because of which wchar_title is pointing at deallocated memory.
Anyone know of a good way to fix this ?
You need to move all three lines of the repeated code into a small utility function.
static void Notification::ConvertToLPCWSTR(const std::string& input, LPWSTR result, size_t result_max_size) {
std::wstring wInfo = std::wstring(input.begin(), input.end());
const wchar_t * wchar_Info = (STRSAFE_LPCWSTR) wInfo.c_str();
StringCchCopy(result, result_max_size, wchar_Info);
}
And call like
ConvertToLPCWSTR(info, nid.szInfo, sizeof(nid.szInfo));

`std::filesystem::path::operator/(/*args*/)` not working as expected

I have a class with an initialiser list in the constructor where one of the fields I'm initialising is a std::filesystem::path but it doesn't seem to be initialising to the expected value.
MyClass::MyClass(
unsigned int deviceSerial,
const std::string& processName
) :
deviceSerial(deviceSerial),
processName(processName),
configFilePath(GetBasePath() / std::to_string(deviceSerial) / ("#" + processName + ".json"))
{
/* Parameter checks */
}
Using the debugger I can see that GetBasePath() is returning exactly what I expect (returns std::filesystem::path with correct path) but the / operator doesn't seem to be having an effect. Once inside the body of the constructor I can see that configFilePath is setup to the result of GetBasePath() without the extra info appended.
I'm using MSVS-2019, I have the C++ language standard set to C++17 and in debug mode I have all optimisations disabled.
I have also tested the following in the body of the class and I still see path as simply the result of GetBasePath() and the extra items are not being appended.
{
auto path = GetBasePath(); // path = "C:/Users/Me/Desktop/Devices"
path /= std::to_string(deviceSerial); // path = "C:/Users/Me/Desktop/Devices"
path /= ("#" + processName + ".json"); // path = "C:/Users/Me/Desktop/Devices"
}
On a slight side note I also tried the above test with += instead of /= and I still see the same results.
Edit
As requested, below is a minimal complete and verifiable example.
#include <Windows.h>
#include <cstdio>
#include <filesystem>
#include <memory>
#include <string>
std::string ExpandPath(const std::string &str) {
auto reqBufferLen = ExpandEnvironmentStrings(str.c_str(), nullptr, 0);
if (reqBufferLen == 0) {
throw std::system_error((int)GetLastError(), std::system_category(),
"ExpandEnvironmentStrings() failed.");
}
auto buffer = std::make_unique<char[]>(reqBufferLen);
auto setBufferLen =
ExpandEnvironmentStrings(str.c_str(), buffer.get(), reqBufferLen);
if (setBufferLen != reqBufferLen - 1) {
throw std::system_error((int)GetLastError(), std::system_category(),
"ExpandEnvironmentStrings() failed.");
}
return std::string{buffer.get(), setBufferLen};
}
int main() {
unsigned int serial = 12345;
std::string procName = "Bake";
std::filesystem::path p(ExpandPath("%USERPROFILE%\\Desktop\\Devices"));
std::printf("Path = %s\n", p.string().c_str());
// p = C:\Users\Me\Desktop\Devices
p /= std::to_string(serial);
std::printf("Path = %s\n", p.string().c_str());
// p = C:\Users\Me\Desktop\Devices
p /= "#" + procName + ".json";
std::printf("Path = %s\n", p.string().c_str());
// p = C:\Users\Me\Desktop\Devices
std::getchar();
}
I've also used this example and tested with `p.append()` and got the same result.
I'd like to give thanks to #rustyx and #Frank for their suggestions, following this advice has led me to discover a bug in the way I create the initial string that gets passed to the path constructor (Also #M.M who found the exact bug while I was typing this answer)
I created a function (that is in use in my class) std::string ExpandPath(const std::string& path) which uses the Windows API to expand any environment variables in a path and return a string. This string is generated from a char* and a count, that count includes the null byte so when creating an string using the constructor variant std::string(char* cstr, size_t len) this includes the null byte in the string itself.
Because I was using the debugger to interrogate the variables it reads C-style strings and stops at the null byte. In my original example I also use printf() as I just happen to prefer this function for output, but again this stops printing at the null byte. If I change the output to use std::cout I can see that the output has the expected path but with an extra space their (the null byte being printed as a space). Using std::cout I see that my paths result as the following with each append:
Path = C:\Users\Me\Desktop\Devices
Path = C:\Users\Me\Desktop\Devices \12345
Path = C:\Users\Me\Desktop\Devices \12345\#Bake.json
Summary:
Bug in my ExpandPath() where
return std::string{buffer.get(), setBufferLen};
Should be
return std::string{buffer.get(), setBufferLen - 1};

C++ from linux to windows: 'does not evaluate to a constant'

I am trying to port this function from Linux to windows:
template<class TDescriptor, class F>
bool TemplatedVocabulary<TDescriptor,F>::loadFromBinaryFile(const std::string &filename) {
fstream f;
f.open(filename.c_str(), ios_base::in|ios::binary);
unsigned int nb_nodes, size_node;
f.read((char*)&nb_nodes, sizeof(nb_nodes));
f.read((char*)&size_node, sizeof(size_node));
f.read((char*)&m_k, sizeof(m_k));
f.read((char*)&m_L, sizeof(m_L));
f.read((char*)&m_scoring, sizeof(m_scoring));
f.read((char*)&m_weighting, sizeof(m_weighting));
createScoringObject();
m_words.clear();
m_words.reserve(pow((double)m_k, (double)m_L + 1));
m_nodes.clear();
m_nodes.resize(nb_nodes+1);
m_nodes[0].id = 0;
char buf[size_node];// fails
int nid = 1;
while (!f.eof()) {
f.read(buf, size_node);
m_nodes[nid].id = nid;
// FIXME
const int* ptr=(int*)buf;
m_nodes[nid].parent = *ptr;
//m_nodes[nid].parent = *(const int*)buf;
m_nodes[m_nodes[nid].parent].children.push_back(nid);
m_nodes[nid].descriptor = cv::Mat(1, F::L, CV_8U);
memcpy(m_nodes[nid].descriptor.data, buf+4, F::L);
m_nodes[nid].weight = *(float*)(buf+4+F::L);
if (buf[8+F::L]) { // is leaf
int wid = m_words.size();
m_words.resize(wid+1);
m_nodes[nid].word_id = wid;
m_words[wid] = &m_nodes[nid];
}
else
m_nodes[nid].children.reserve(m_k);
nid+=1;
}
f.close();
return true;
}
This line:
char buf[size_node];
will not compile, giving the error:
expression did not evaluate to a constant.
I have tried using:
std::vector<char> buf(size_node)
and:
char buf[size_node] = new char[];
but I see the same error. It seems like this is related to a run time constant vs compile time constant, as stated in the answer here:
Tuple std::get() Not Working for Variable-Defined Constant
But I am not sure how to get around it in this case. Thank you.
It should be
char *buf = new char[size_node];
Remember to delete the memory after use.
Or, just use std::vector. It's much safer.
std::vector<char> buf(size_node);
Then you'd have to change how buf is used. For example:
f.read(buf, size_node);
should become
f.read(buf.data(), size_node); //Only C++11

extract domain between two words

I have in a log file some lines like this:
11-test.domain1.com Logged ...
37-user1.users.domain2.org Logged ...
48-me.server.domain3.net Logged ...
How can I extract each domain without the subdomains? Something between "-" and "Logged".
I have the following code in c++ (linux) but it doesn't extract well. Some function which is returning the extracted string would be great if you have some example of course.
regex_t preg;
regmatch_t mtch[1];
size_t rm, nmatch;
char tempstr[1024] = "";
int start;
rm=regcomp(&preg, "-[^<]+Logged", REG_EXTENDED);
nmatch = 1;
while(regexec(&preg, buffer+start, nmatch, mtch, 0)==0) /* Found a match */
{
strncpy(host, buffer+start+mtch[0].rm_so+3, mtch[0].rm_eo-mtch[0].rm_so-7);
printf("%s\n", tempstr);
start +=mtch[0].rm_eo;
memset(host, '\0', strlen(host));
}
regfree(&preg);
Thank you!
P.S. no, I cannot use perl for this because this part is inside of a larger c program which was made by someone else.
EDIT:
I replace the code with this one:
const char *p1 = strstr(buffer, "-")+1;
const char *p2 = strstr(p1, " Logged");
size_t len = p2-p1;
char *res = (char*)malloc(sizeof(char)*(len+1));
strncpy(res, p1, len);
res[len] = '\0';
which is extracting very good the whole domain including subdomains.
How can I extract just the domain.com or domain.net from abc.def.domain.com ?
is strtok a good option and how can I calculate which is the last dot ?
#include <vector>
#include <string>
#include <boost/regex.hpp>
int main()
{
boost::regex re(".+-(?<domain>.+)\\s*Logged");
std::string examples[] =
{
"11-test.domain1.com Logged ...",
"37-user1.users.domain2.org Logged ..."
};
std::vector<std::string> vec(examples, examples + sizeof(examples) / sizeof(*examples));
std::for_each(vec.begin(), vec.end(), [&re](const std::string& s)
{
boost::smatch match;
if (boost::regex_search(s, match, re))
{
std::cout << match["domain"] << std::endl;
}
});
}
http://liveworkspace.org/code/1983494e6e9e884b7e539690ebf98eb5
something like this with boost::regex. Don't know about pcre.
Is the in a standard format?
it appears so, is there a split function?
Edit:
Here is some logic.
Iterate through each domain to be parsed
Find a function to locate the index of the first string "-"
Next find the index of the second string minus the first string "Logged"
Now you have the full domain.
Once you have the full domain "Split" the domain into your object of choice (I used an array)
now that you have the array broken apart locate the index of the value you wish to reassemble (concatenate) to capture only the domain.
NOTE Written in C#
Main method which defines the first value and the second value
`static void Main(string[] args)
{
string firstValue ="-";
string secondValue = "Logged";
List domains = new List { "11-test.domain1.com Logged", "37-user1.users.domain2.org Logged","48-me.server.domain3.net Logged"};
foreach (string dns in domains)
{
Debug.WriteLine(Utility.GetStringBetweenFirstAndSecond(dns, firstValue, secondValue));
}
}
`
Method to parse the string:
`public string GetStringBetweenFirstAndSecond(string str, string firstStringToFind, string secondStringToFind)
{
string domain = string.Empty;
if(string.IsNullOrEmpty(str))
{
//throw an exception, return gracefully, whatever you determine
}
else
{
//This can all be done in one line, but I broke it apart so it can be better understood.
//returns the first occurrance.
//int start = str.IndexOf(firstStringToFind) + 1;
//int end = str.IndexOf(secondStringToFind);
//domain = str.Substring(start, end - start);
//i.e. Definitely not quite as legible, but doesn't create object unnecessarily
domain = str.Substring((str.IndexOf(firstStringToFind) + 1), str.IndexOf(secondStringToFind) - (str.IndexOf(firstStringToFind) + 1));
string[] dArray = domain.Split('.');
if (dArray.Length > 0)
{
if (dArray.Length > 2)
{
domain = string.Format("{0}.{1}", dArray[dArray.Length - 2], dArray[dArray.Length - 1]);
}
}
}
return domain;
}
`

How to get the stem of a filename from a path?

I want to extract a const char* filename from a const char* filepath. I tried with regex but failed:
const char* currentLoadedFile = "D:\files\file.lua";
char fileName[256];
if (sscanf(currentLoadedFile, "%*[^\\]\\%[^.].lua", fileName)) {
return (const char*)fileName; // WILL RETURN "D:\files\file!!
}
The issue is that "D:\files\file" will be returned and not the wanted "file"(note: without ".lua")
What about using std::string?
e.g.
std::string path("d:\\dir\\subdir\\file.ext");
std::string filename;
size_t pos = path.find_last_of("\\");
if(pos != std::string::npos)
filename.assign(path.begin() + pos + 1, path.end());
else
filename = path;
Just use boost::filesystem.
#include <boost/filesystem.hpp>
std::string filename_noext;
filename_noext = boost::filesystem::path("D:\\files\\file.lua").stem().string().
const char* result_as_const_char = filename_noext.c_str();
or alternatively, if you want to introduce bugs yourself :
// have fun defining that to the separator of the target OS.
#define PLATFORM_DIRECTORY_SEPARATOR '\\'
// the following code is guaranteed to have bugs.
std::string input = "D:\\files\\file.lua";
std::string::size_type filename_begin = input.find_last_of(PLATFORM_DIRECTORY_SEPERATOR);
if (filename_begin == std::string::npos)
filename_begin = 0;
else
filename_begin++;
std::string::size_type filename_length = input.find_last_of('.');
if (filename_length != std::string::npos)
filename_length = filename_length - filename_begin;
std::string result = input.substr(filename_begin, filename_length);
const char* bugy_result_as_const_char = result.c_str();
You can do this portably and easily using the new filesystem library in C++17.
#include <cstdint>
#include <cstdio>
#include <filesystem>
int main()
{
std::filesystem::path my_path("D:/files/file.lua");
std::printf("filename: %s\n", my_path.filename().u8string().c_str());
std::printf("stem: %s\n", my_path.stem().u8string().c_str());
std::printf("extension: %s\n", my_path.extension().u8string().c_str());
}
Output:
filename: file.lua
stem: file
extension: .lua
Do note that for the time being you may need to use #include <experimental/fileystem> along with std::experimental::filesystem instead until standard libraries are fully conforming.
For more documentation on std::filesystem check out the filesystem library reference.
You can easily extract the file:
int main()
{
char pscL_Dir[]="/home/srfuser/kush/folder/kushvendra.txt";
char pscL_FileName[50];
char pscL_FilePath[100];
char *pscL;
pscL=strrchr(pscL_Dir,'/');
if(pscL==NULL)
printf("\n ERROR :INvalid DIr");
else
{
strncpy(pscL_FilePath,pscL_Dir,(pscL-pscL_Dir));
strcpy(pscL_FileName,pscL+1);
printf("LENTH [%d}\n pscL_FilePath[%s]\n pscL_FileName[%s]",(pscL-pscL_Dir),pscL_FilePath,pscL_FileName);
}
return 0;
}
output:
LENTH [25}
pscL_FilePath[/home/srfuser/kush/folder]
pscL_FileName[kushvendra.txt
Here you can find an example. I'm not saying it's the best and I'm sure you could improve on that but it uses only standard C++ (anyway at least what's now considered standard).
Of course you won't have the features of the boost::filesystem (those functions in the example play along with plain strings and do not guarantee/check you'll actually working with a real filesystem path).
// Set short name:
char *Filename;
Filename = strrchr(svFilename, '\\');
if ( Filename == NULL )
Filename = svFilename;
if ( Filename[0] == '\\')
++Filename;
if ( !lstrlen(Filename) )
{
Filename = svFilename;
}
fprintf( m_FileOutput, ";\n; %s\n;\n", Filename );
You could use the _splitpath_s function to break a path name into its components. I don't know if this is standard C or is Windows specific. Anyway this is the function:
#include <stdlib.h>
#include <string>
using std::string;
bool splitPath(string const &path, string &drive, string &directory, string &filename, string &extension) {
// validate path
drive.resize(_MAX_DRIVE);
directory.resize(_MAX_DIR);
filename.resize(_MAX_FNAME);
extension.resize(_MAX_EXT);
errno_t result;
result = _splitpath_s(path.c_str(), &drive[0], drive.size(), &directory[0], directory.size(), &filename[0], filename.size(), &extension[0], extension.size());
//_splitpath(path.c_str(), &drive[0], &directory[0], &filename[0], &extension[0]); //WindowsXp compatibility
_get_errno(&result);
if (result != 0) {
return false;
} else {
//delete the blank spaces at the end
drive = drive.c_str();
directory = directory.c_str();
filename = filename.c_str();
extension = extension.c_str();
return true;
}
}
It is a lot easier and safe to use std::string but you could modify this to use TCHAR* (wchar, char)...
For your specific case:
int main(int argc, char *argv[]) {
string path = argv[0];
string drive, directory, filename, extension;
splitPath(path, drive, directory, filename, extension);
printf("FILE = %s%s", filename.c_str(), extension.c_str());
return 0;
}
If you are going to display a filename to the user on Windows you should respect their shell settings (show/hide extension etc).
You can get a filename in the correct format by calling SHGetFileInfo with the SHGFI_DISPLAYNAME flag.