Can't Create Dynamic Folder Name - c++

In C++ I want to create a dynamic folder each time I run my program.
#include <direct.h> // mkdir
#include <iostream> // std
#include <iomanip> // put_time
int main(){
time_t rawtime;
struct tm * timeinfo;
char buffer[40];
time(&rawtime);
timeinfo = localtime(&rawtime);
//strftime(buffer, sizeof(buffer), "%d-%m-%Y %I:%M:%S", timeinfo);
strftime(buffer, sizeof(buffer), "%d_%m_%Y_%I_%M_%S", timeinfo);
std::string path = "C:/example/";
path.append(std::string(buffer));
mkdir(path.c_str());
//system("pause");
return 0;
}
I want to create a folder named like "Example/03_03_2016_20_22_26", but the code above will not create the folder I want.
If I remove the path.append(std::string(buffer)); line, it will create the folder named example in my C directory.
However I want a folder named according to the complete date and time.
Where am I wrong or what am I missing?

I use this code for a similar purpose in my project (SAVE_DIR is a macro definition):
#include <time.h>
#include <iomanip>
#include <sstream>
std::ostringstream pathstr; // a convenient way to construct strings
std::time_t now = std::time(nullptr); // get the current time
// insert the required parts into the stream
pathstr << SAVE_DIR
<< std::put_time(std::localtime(&now), "%Y_%m_%d_%H_%M_%S") << ".png";
std::string path = pathstr.str(); // and the result as std::str
Output:
/home/user/prog/render/rt/saves/2016_03_03_23_10_50.png
This has the benefit of being pure C++, though it may look a bit clumsy, depending on your taste.
As for what your code may fail, I'd watch the string values in a debugger first, and then save the return value of mkdir() and check it against the specifications: POSIX mkdir().

I guess the issue is in the slash '/'.
On Windows better use the backslash.
Try
std::string path="C:\\example\\"

Related

how to get current time zone city name like America/Los_Angeles

I tried strftime, which has %z and %Z, but these are outputs like +0800 and PST. I'd like to get the longer name like America/Los_Angeles. Is there a function call to do this?
There is not a standard way to do this until C++20, and even then only the latest MSVC has implemented it to date (gcc is getting close).
In C++20 there is a type std::chrono::time_zone which has a member function called name() which will return a string such as "America/Los_Angeles".
It might be used like this:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std;
using namespace std::chrono;
zoned_time local_now{"America/Los_Angeles", system_clock::now()};
cout << local_now << " " << local_now.get_time_zone()->name() << '\n';
}
Which just output for me:
2022-12-31 07:34:41.482431 PST America/Los_Angeles
Or if your computer's local time zone is currently set to "America/Los_Angeles", then the zoned_time construction could look like this instead:
zoned_time local_now{current_zone(), system_clock::now()};
If all you want is the time zone name, and not the current time, this can be further simplified to just:
cout << current_zone()->name() << '\n';
Prior to C++20 the only way I'm aware of to get functionality like this is to use my free, open-source C++20 chrono preview library which will work with C++11/14/17.
One way — I must admit, a decidedly imperfect way — is to read the symbolic link /etc/localtime:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#define LOCALTIME "/etc/localtime"
int main()
{
char buf[100];
int r = readlink(LOCALTIME, buf, sizeof(buf)-1);
if(r < 0) {
fprintf(stderr, "can't read link %s: %s\n", LOCALTIME, strerror(errno));
exit(1);
}
buf[r] = '\0';
char *name = buf;
char *p1 = strstr(buf, "zone");
if(p1 != NULL) {
char *p2;
p2 = strstr(p1 + 1, "zone");
if(p2 != NULL) p1 = p2;
p2 = strchr(p1, '/');
if(p2 != NULL)
name = p2 + 1;
}
printf("%s\n", name);
}
This will work on most Unix-like systems, including Linux and MacOS. It will not work on Windows, which AFAIK does not use the IANA tz database at all. It will not work on systems where /etc/localtime is a file, rather than a symbolic link to one of the zoneinfo files.
If /etc/localtime is a file, there is no good way to determine which zone name it represents. I believe you would have to compare it to all of the files underneath /usr/share/zoneinfo, looking for matching contents.
I'm not sure what magic technique Howard uses in his C++ solution.
(But I mean no disrespect with that word "magic".)

Using Preprocessor DATE dynamically

I'm trying to use __DATE__ in C++Builder, and I need to use it dynamically. For example, if a user click on a button, the label containing __DATE__ will update following the system date.
I did that for now:
label1->Text = "Data: " __DATE__;
This is in a function to set the date, called DateTime(). For the button I already did the click event, but I need the DateTime() to run dynamically.
__DATE__ is a compile-time constant. It is the date on which the .cpp file is compiled. This is not what you want in this situation.
C++Builder's RTL has a Sysutils::Date() function that you can use instead, eg:
#include <System.SysUtils.hpp>
label1->Text = _T("Data: ") + Date().DateString();
Date() returns a TDateTime representing the current system date (if you want to include time as well, use Sysutils::Now() instead). Its DateString() method formats the TDateTime into a String using the user's locale settings. If you want to format the TDateTime yourself, you can use its FormatString() method for that, eg:
#include <System.SysUtils.hpp>
label1->Text = _T("Data: ") + Date().FormatString(_T("yyyy-mm-dd"));
or:
label1->Text = Date().FormatString(_T("'Data: 'yyyy-mm-dd"));
If you want a more standard C++ solution, look at the std::time() and std:::strftime() functions, eg:
#include <ctime>
std::time_t now_c = std::time(nullptr);
std::tm now_tm = *std::localtime(&now_c);
char buffer[11] = {};
std::strftime(buffer, sizeof(buffer), "%Y-%m-%d", &now_tm);
label1->Text = _T("Data: ") + String(buffer);
or:
label1->Text = String().sprintf(_T("Data: %s"), buffer);
Or, look at the <chrono> library introduced in C++11, such as std::chrono::system_clock, eg:
#include <chrono>
#include <ctime>
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t now_c = std::chrono::system_clock::to_time_t(now);
std::tm now_tm = *std::localtime(&now_c);
char buffer[11] = {};
std::strftime(buffer, sizeof(buffer), "%Y-%m-%d", &now_tm);
label1->Text = _T("Data: ") + String(buffer);
or:
label1->Text = String().sprintf(_T("Data: %s"), buffer);
Alternatively:
#include <chrono>
#include <ctime>
#include <sstream>
#include <iomanip>
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t now_c = std::chrono::system_clock::to_time_t(now);
std::tm now_tm = *std::localtime(&now_c);
std::wostringstream oss;
oss << L"Data: " << std::put_time(&now_tm, L"%Y-%m-%d");
label1->Text = oss.str().c_str();
The __DATE__ symbol is a pre-processor macro, hence it is only defined at compile time.
That means that the actual value of __DATE__ will not change during the execution of your program. It will be the time of your compilation. Forever the same value in the executable that you have just compiled.
If you need date string that reflects the current system clock/date, then you will need to use some function that queries the system for the current, as time(). Definitely not a compile-time-pre-processor macro string as __DATE__. See other ctime functions to assist you in formatting the desired string.
Finally, about building the string: you will need to compose strings at runtime much as sprintf does. Your construction "Data: " __DATE__ is just valid because you are again concatenating string as compilation time (it is the compiler pre-processor the one doing the concatenation, no your program). Here you can read about this capability of the C pre-processor. Also,here is described that this is a C99 standard behaviour, but cannot tell if it was not defined in an earlier C standard.

How to create folder in %appdata%, create .bat file in it, and then execute it?

I'm creating C++ code that will create some .bat file and store it in the %appdata% folder. I've successfully to created the file, but still fail to create the folder and execute it.
Below is my simple code, it doesn't look simple but it works to create .bat file in %appdata%, maybe someone can help me to find the simple one.
#include <iostream>
#include <stdio.h>
#include <fstream>
#include <sstream>
#include <string>
#include <windows.h>
#include <direct.h>
int main(int argc, char **argv) {
using namespace std;
std::ofstream aaa;
ostringstream aaa;
aaa.open(aaa1.str());
aaa1 << getenv("appdata") << "/"
<< "test.bat";
aaa.open(aaa1.str());
Updater << "#echo on" << endl;
Updater << "echo \"on\"" << endl;
return 0;
}
The code successfully creates the .bat file in %appdata%, but I need to store in new folder in %appdata%, say New Folder, and then execute the .bat file.
Create Directory
1st get the path using _dupenv_s() in string add new folder name "\New Folder"
2nd Create Directory using _mkdir(str.c_str());
3rd Create "test.bat" using std::ofstream outf(str);
#include "stdafx.h"
#include<fstream>
#include<iostream>
#include<conio.h>
#include<direct.h>
using std::cout;
using std::cin;
using std::endl;
int tmain(int argc, TCHAR* argv[])
{
char *pValue;
size_t len;
errno_t err = _dupenv_s(&pValue, &len, "APPDATA");
std::string NewFile = "\\new";
std::string str(pValue);
str = str + NewFile;
_mkdir(str.c_str());
str = str + "\\Sample.bat"; //
std::ofstream outf(str);
if (!outf)
{
printf("error ");
}
outf << "this is line1" << endl;
outf << "line 2" << endl;
return 0;
}
Please! Don't Forgot to Vote If its Helps
Creating/running an executable in a user writable location is something to be careful with (exploit people into running your process elevated, then running an attack payload), otherwise just a couple of things to tie together.
On Windows, most of those environment variables exist for legacy / compatibility reasons, SHGetKnownFolderPath is the modern way to find the folders. It allocates enough space for the path, be careful with manual memory from C-API, get it a unique_ptr or wstring as soon as possible. It works from Vista, there are older API's if really needed.
wchar_t *str = nullptr;
SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_DEFAULT, NULL, &str); // CHECK RETURN
...use str...
CoTaskMemFree(str);
Also be aware of Unicode and spaces in file paths.
Processes have two options, there is the system(command_line) in the cstdlib header, or for advanced use check out the Windows CreateProcessW. Something like:
STARTTUPINFO startup;
startup.cb = sizeof(startup);
PROCESS_INFORMATION pi;
CreateProcessW(NULL, L"cmd.exe /C C:\\ThePath\\myfile.bat", NULL, NULL, FALSE, 0, NULL, NULL, &startup, &pi);
Obviously specific to Windows. Linux, Mac, etc. have their own filesystem layouts and security.
C++ fstream won't create directories for you automatically. You could set up such directories as part of an installer, but to do it at runtime C++17 has std::filesystem::create_directories, which takes a path. If you can't use C++17, use CreateDirectory or _mkdir. Again on Windows be aware of Unicode.

How do I convert a string in seconds to time in C++

I have a string that stores the no of seconds since a process started. I need to convert this string with the no of seconds to time in C++. I need to subtract this time from the current time to get the time that this process started. I am confused and I do not know how to go about it. Please could someone help me out. I am a bit new to C++
Maybe you could try out Boost Time Library (http://www.boost.org/doc/libs/1_53_0/libs/timer/doc/index.html) or std::chrono if you're using newer compiler (as suggested below) and wish to stay within STL.
Something like that could work:
#include <chrono>
#include <string>
using namespace std::chrono;
std::string elapsed_time_in_s = "123456";
system_clock::time_point then = system_clock::now() -
std::chrono::seconds(std::stoll(elapsed_time_in_s));
time_t then_as_time_t = system_clock::to_time_t(then);
#include <sstream>
///
std::stringstream strs(seconds_string);
unsigned int tempTime=0;
if(!(strs >> tempTime))
//error
//calculate around with tempTime
if(!(strs << tempTime)
//error
if(!(strs >> seconds_string)
//error
//new string with the current time
You can use standard <time.h> routines (time, and gmtime or localtime).
For example:
void PrintProcessStartTimeAndDate(int numOfSeconds)
{
time_t rawtime;
struct tm* ptm;
time(&rawtime);
rawtime -= numOfSeconds;
ptm = gmtime(&rawtime); // or localtime(&rawtime);
printf("Process started at %.2d:%.2d:%.2d on %.2d/%.2d/%.2d\n",
ptm->tm_hour,ptm->tm_min,ptm->tm_sec,ptm->tm_mday,ptm->tm_mon+1,ptm->tm_year+1900);
}
Please note that gmtime and localtime routines are not thread-safe.
This fact is due to the pointer-to-static-structure that each one of them returns.

C++ write to file error with full PATH from GetEnvironmentVariable()

I'm noob in C++ but wanting to learn. I have a little program that writes some info to my \etc\hosts in Windows; I get the %WINDIR% variable via GetEnvironmentVariable(), if I put the full path manually everything is ok, but when I substitute with WINDIR variable my code isn't compiling. I know I don't do something right.
#include <windows.h>
#include <ios>
#include <fstream>
char buffer[1000];
int main() {
GetEnvironmentVariable("WINDIR",(char*)&buffer,sizeof(buffer));
std::ofstream log;
log.open("%s\\system32\\drivers\\etc\\hosts", buffer);
log << "127.0.0.1 domain.com\n" << std::endl;
return 0;
}
I get really ugly errors like:
C:\Documents and Settings\xtmtrx\Desktop\coding\windir.cpp no matching function for call to `std::basic_ofstream<char, std::char_traits<char> >::open(const char[30], char[1000])'
ofstream cannot format the path for you. You need to do that separately, eg:
#include <windows.h>
#include <ios>
#include <fstream>
char buffer[1000] = {0};
int main() {
GetEnvironmentVariable("WINDIR",buffer,sizeof(buffer));
strcat(buffer, "\\system32\\drivers\\etc\\hosts");
std::ofstream log;
log.open(buffer, ios_base::ate);
log << "127.0.0.1 domain.com\n" << std::endl;
return 0;
}
FYI, you should use GetWindowsDirectory(), GetSystemDirectory(), SHGetSpecialFolderPath() or SHGetKnownFolderPath() instead of GetEnvironmentVariable(). And you should use PathCombine() when concantenating paths together so it can ensure the slashes are correct.
open("%s\\system32\\drivers\\etc\\hosts", buffer); open doesn't understand format strings..you are using %s does not make sense. learn here
Try like this:
GetEnvironmentVariable("WINDIR",buffer,sizeof(buffer));
strcat(buffer, "\\system32\\drivers\\etc\\hosts");
std::ofstream log;
log.open(buffer.str().c_str(), ios_base::ate);
You need to concate the string together like this:
LPTSTR windir[MAX_PATH];
LPTSTR fullpath[MAX_PATH];
GetWindowsDirectory(windir, MAX_PATH);
if(PathCombine(fullpath, windir, _T("system32\\drivers\\etc\\hosts")) != NULL) {
std::ofstream log;
log.open(buffer, ios_base::ate);
log << "127.0.0.1 domain.com\n" << std::endl;
}
At first you need to concate the directory and the file part with PathCombine. Then you can open the file and write the content. You should also note that you need admin permissions to change this file and some antivirus programmes may reject the access of the hosts file.